Respuesta más básica
Estoy usando el sql simple a continuación para que todo sea lo más claro y legible posible. En su proyecto puede utilizar los métodos de conveniencia de Android. El db
objeto que se utiliza a continuación es una instancia de SQLiteDatabase .
Crear tabla FTS
db.execSQL("CREATE VIRTUAL TABLE fts_table USING fts3 ( col_1, col_2, text_column )");
Esto podría ir en el onCreate()
método de su SQLiteOpenHelper
clase extendida .
Rellenar tabla FTS
db.execSQL("INSERT INTO fts_table VALUES ('3', 'apple', 'Hello. How are you?')");
db.execSQL("INSERT INTO fts_table VALUES ('24', 'car', 'Fine. Thank you.')");
db.execSQL("INSERT INTO fts_table VALUES ('13', 'book', 'This is an example.')");
Sería mejor usar SQLiteDatabase # insert o declaraciones preparadas que execSQL
.
Consultar tabla FTS
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_table WHERE fts_table MATCH ?", selectionArgs);
También puede utilizar el método de consulta SQLiteDatabase # . Tenga en cuenta la MATCH
palabra clave.
Respuesta más completa
La tabla FTS virtual anterior tiene un problema. Cada columna está indexada, pero esto es una pérdida de espacio y recursos si algunas columnas no necesitan indexarse. La única columna que necesita un índice FTS es probablemente text_column
.
Para resolver este problema usaremos una combinación de una tabla regular y una tabla FTS virtual. La tabla FTS contendrá el índice, pero ninguno de los datos reales de la tabla normal. En su lugar, tendrá un enlace al contenido de la tabla normal. Esto se denomina tabla de contenido externo .
Crea las tablas
db.execSQL("CREATE TABLE example_table (_id INTEGER PRIMARY KEY, col_1 INTEGER, col_2 TEXT, text_column TEXT)");
db.execSQL("CREATE VIRTUAL TABLE fts_example_table USING fts4 (content='example_table', text_column)");
Tenga en cuenta que tenemos que usar FTS4 para hacer esto en lugar de FTS3. FTS4 no es compatible con Android antes de la versión 11 de API. Puede (1) proporcionar solo la funcionalidad de búsqueda para API> = 11, o (2) usar una tabla FTS3 (pero esto significa que la base de datos será más grande porque existe la columna de texto completo en ambas bases de datos).
Rellenar las tablas
db.execSQL("INSERT INTO example_table (col_1, col_2, text_column) VALUES ('3', 'apple', 'Hello. How are you?')");
db.execSQL("INSERT INTO example_table (col_1, col_2, text_column) VALUES ('24', 'car', 'Fine. Thank you.')");
db.execSQL("INSERT INTO example_table (col_1, col_2, text_column) VALUES ('13', 'book', 'This is an example.')");
(Nuevamente, hay mejores formas de hacer inserciones que con execSQL
. Solo lo estoy usando por su legibilidad).
Si intentara hacer una consulta FTS ahora fts_example_table
, no obtendría resultados. La razón es que cambiar una mesa no cambia automáticamente la otra mesa. Tienes que actualizar manualmente la tabla FTS:
db.execSQL("INSERT INTO fts_example_table (docid, text_column) SELECT _id, text_column FROM example_table");
( docid
Es como rowid
para una tabla normal). Debe asegurarse de actualizar la tabla FTS (para que pueda actualizar el índice) cada vez que realice un cambio (INSERT, DELETE, UPDATE) en la tabla de contenido externo. Esto puede resultar engorroso. Si solo está creando una base de datos rellenada previamente, puede hacer
db.execSQL("INSERT INTO fts_example_table(fts_example_table) VALUES('rebuild')");
que reconstruirá toda la tabla. Sin embargo, esto puede ser lento, por lo que no es algo que desee hacer después de cada pequeño cambio. Lo haría después de terminar todas las inserciones en la tabla de contenido externo. Si necesita mantener las bases de datos sincronizadas automáticamente, puede usar activadores . Vaya aquí y desplácese un poco hacia abajo para encontrar direcciones.
Consultar las bases de datos
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_example_table WHERE fts_example_table MATCH ?", selectionArgs);
Esto es lo mismo que antes, excepto que esta vez solo tiene acceso a text_column
(y docid
). ¿Qué sucede si necesita obtener datos de otras columnas en la tabla de contenido externo? Dado que el docid
de la tabla FTS coincide con rowid
(y en este caso _id
) de la tabla de contenido externo, puede usar una combinación. (Gracias a esta respuesta por ayudar con eso).
String sql = "SELECT * FROM example_table WHERE _id IN " +
"(SELECT docid FROM fts_example_table WHERE fts_example_table MATCH ?)";
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery(sql, selectionArgs);
Otras lecturas
Revise estos documentos detenidamente para ver otras formas de usar tablas virtuales FTS:
Notas adicionales