Réponse la plus basique
J'utilise le SQL clair ci-dessous pour que tout soit aussi clair et lisible que possible. Dans votre projet, vous pouvez utiliser les méthodes pratiques Android. L' db
objet utilisé ci-dessous est une instance de SQLiteDatabase .
Créer une table FTS
db.execSQL("CREATE VIRTUAL TABLE fts_table USING fts3 ( col_1, col_2, text_column )");
Cela pourrait aller dans la onCreate()
méthode de votre SQLiteOpenHelper
classe étendue .
Remplir la table 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.')");
Il serait préférable d'utiliser des instructions SQLiteDatabase # insert ou préparées que execSQL
.
Table FTS de requête
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_table WHERE fts_table MATCH ?", selectionArgs);
Vous pouvez également utiliser la méthode de requête SQLiteDatabase # . Notez le MATCH
mot - clé.
Réponse plus complète
La table FTS virtuelle ci-dessus présente un problème. Chaque colonne est indexée, mais c'est un gaspillage d'espace et de ressources si certaines colonnes n'ont pas besoin d'être indexées. La seule colonne qui nécessite un index FTS est probablement le text_column
.
Pour résoudre ce problème, nous utiliserons une combinaison d'une table régulière et d'une table FTS virtuelle. La table FTS contiendra l'index mais aucune des données réelles de la table régulière. Au lieu de cela, il aura un lien vers le contenu de la table régulière. C'est ce qu'on appelle une table de contenu externe .
Créer les tableaux
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)");
Notez que nous devons utiliser FTS4 pour ce faire plutôt que FTS3. FTS4 n'est pas pris en charge dans Android avant la version 11 de l'API. Vous pouvez soit (1) fournir uniquement une fonctionnalité de recherche pour API> = 11, ou (2) utiliser une table FTS3 (mais cela signifie que la base de données sera plus grande car la colonne de texte intégral existe dans les deux bases de données).
Remplir les tableaux
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.')");
(Encore une fois, il existe de meilleures façons de faire des insertions qu'avec execSQL
. Je ne l'utilise que pour sa lisibilité.)
Si vous essayez de faire une requête FTS maintenant, fts_example_table
vous n'obtiendrez aucun résultat. La raison en est que la modification d'une table ne modifie pas automatiquement l'autre table. Vous devez mettre à jour manuellement la table FTS:
db.execSQL("INSERT INTO fts_example_table (docid, text_column) SELECT _id, text_column FROM example_table");
( Cela docid
ressemble rowid
à une table normale.) Vous devez vous assurer de mettre à jour la table FTS (afin qu'elle puisse mettre à jour l'index) chaque fois que vous apportez une modification (INSERT, DELETE, UPDATE) à la table de contenu externe. Cela peut devenir fastidieux. Si vous créez uniquement une base de données préremplie, vous pouvez faire
db.execSQL("INSERT INTO fts_example_table(fts_example_table) VALUES('rebuild')");
qui reconstruira toute la table. Cela peut être lent, cependant, ce n'est donc pas quelque chose que vous voulez faire après chaque petit changement. Vous le feriez après avoir terminé toutes les insertions sur la table de contenu externe. Si vous avez besoin de synchroniser automatiquement les bases de données, vous pouvez utiliser des déclencheurs . Allez ici et faites défiler un peu pour trouver des directions.
Interroger les bases de données
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_example_table WHERE fts_example_table MATCH ?", selectionArgs);
C'est la même chose qu'avant, sauf que cette fois, vous n'avez accès qu'à text_column
(et docid
). Que faire si vous avez besoin d'obtenir des données à partir d'autres colonnes de la table de contenu externe? Puisque le docid
de la table FTS correspond au rowid
(et dans ce cas _id
) de la table de contenu externe, vous pouvez utiliser une jointure. (Merci à cette réponse pour votre aide.)
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);
Lectures complémentaires
Parcourez attentivement ces documents pour voir d'autres façons d'utiliser les tables virtuelles FTS:
Notes complémentaires
- Les opérateurs de définition (AND, OR, NOT) dans les requêtes SQLite FTS ont la syntaxe de requête standard et la syntaxe de requête améliorée . Malheureusement, Android ne prend apparemment pas en charge la syntaxe de requête améliorée (voir ici , ici , ici et ici ). Cela signifie que mélanger ET et OU devient difficile (nécessitant l'utilisation
UNION
ou la vérification PRAGMA compile_options
semble-t-il). Très malheureux. Veuillez ajouter un commentaire s'il y a une mise à jour dans ce domaine.