J'ai du mal à comprendre comment utiliser la recherche de texte intégral (FTS) avec Android. J'ai lu le documentation SQLite sur les extensions FTS3 et FTS4 . Et je sais il est possible de le faire sur Android . Cependant, j'ai du mal à trouver des exemples que je puisse comprendre.
Une table de base de données SQLite (nommée example_table
) a 4 colonnes. Cependant, il n'y a qu'une seule colonne (nommée text_column
) qui doit être indexé pour une recherche en texte intégral. Chaque rangée de text_column
contient du texte dont la longueur varie de 0 à 1 000 mots. Le nombre total de lignes est supérieur à 10 000.
text_column
?Notes complémentaires:
example_table
) serait inefficace pour les requêtes non-FTS .text_column
dans la table FTS ne serait pas souhaitable. Cet article suggère d'utiliser un table de contenu externe .J'utilise la plaine sql ci-dessous pour que tout soit aussi clair et lisible que possible. Dans votre projet, vous pouvez utiliser les méthodes pratiques Android. L'objet db
utilisé ci-dessous est une instance de SQLiteDatabase .
db.execSQL("CREATE VIRTUAL TABLE fts_table USING fts3 ( col_1, col_2, text_column )");
Cela pourrait aller dans la méthode onCreate()
de votre classe étendue SQLiteOpenHelper
.
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 SQLiteDatabase # insert ou instructions préparées plutôt que execSQL
.
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_table WHERE fts_table MATCH ?", selectionArgs);
Vous pouvez également utiliser la méthode SQLiteDatabase # query . Notez le mot clé MATCH
.
La table FTS virtuelle ci-dessus a un problème avec elle. 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 allons utiliser une combinaison d’une table standard et d’une table FTS virtuelle. La table FTS contiendra l'index mais aucune des données réelles de la table normale. Au lieu de cela, il y aura un lien vers le contenu de la table standard. Ceci s'appelle un table de contenu externe .
Créez les tables
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 faire cela plutôt que FTS3. FTS4 n'est pas pris en charge dans Android avant la version 11 de l'API. Vous pouvez (1) uniquement fournir une fonctionnalité de recherche pour l'API> = 11 ou (2) utiliser une table FTS3 (mais cela signifie que sera plus grande parce que 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, les insertions sont meilleures qu'avec execSQL
. Je l'utilise simplement pour sa lisibilité.)
Si vous essayez maintenant de faire une requête FTS sur 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");
(docid
est semblable à rowid
pour une table ordinaire.) 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 lourd. Si vous ne faites qu'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, alors ce n'est pas quelque chose que vous voulez faire après chaque petit changement. Vous le feriez après avoir terminé toutes les insertions de la table de contenu externe. Si vous devez synchroniser automatiquement les bases de données, vous pouvez utiliser déclencheurs . Allez ici et descendez un peu pour trouver les 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 que précédemment, sauf que cette fois, vous avez uniquement accès à text_column
(Et docid
). Et si vous avez besoin d'obtenir des données d'autres colonnes de la table de contenu externe? Étant donné que 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 l'aide avec ça.)
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);
Parcourez attentivement ces documents pour découvrir d'autres méthodes d'utilisation des tables virtuelles FTS:
UNION
) _ ou en vérifiant PRAGMA compile_options
semble-t-il) Très regrettable, veuillez ajouter un commentaire s’il ya une mise à jour dans ce domaine.N'oubliez pas lorsque vous utilisez le contenu de pour reconstruire la table fts.
Je fais cela avec un trigger sur update, insert, delete