maggior risposta di base
Sto utilizzando SQL pianura sottostante in modo che tutto sia più chiaro e leggibile possibile. Nel tuo progetto puoi utilizzare i metodi di convenienza Android. L'oggetto db
utilizzato di seguito è un'istanza di SQLiteDatabase.
Create FTS Table
db.execSQL("CREATE VIRTUAL TABLE fts_table USING fts3 (col_1, col_2, text_column)");
Questo potrebbe andare nel metodo del vostro esteso SQLiteOpenHelper
classe onCreate()
.
Populate FTS Table
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.')");
Sarebbe meglio usare SQLiteDatabase#insert o prepared statements di execSQL
.
Query FTS Table
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_table WHERE fts_table MATCH ?", selectionArgs);
si potrebbe anche utilizzare il metodo SQLiteDatabase#query. Nota la parola chiave MATCH
.
Fuller Risposta
La tabella FTS virtuale di cui sopra ha un problema con esso. Ogni colonna è indicizzata, ma questo è uno spreco di spazio e risorse se alcune colonne non hanno bisogno di essere indicizzate. L'unica colonna che ha bisogno di un indice FTS è probabilmente il text_column
.
Per risolvere questo problema verrà utilizzata una combinazione di una tabella normale e una tabella FTS virtuale. La tabella FTS conterrà l'indice ma nessuno dei dati effettivi dalla tabella normale. Invece avrà un link al contenuto della tabella normale. Questo è chiamato external content table.
creare le tabelle
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)");
Nota che dobbiamo usare FTS4 per fare questo, piuttosto che FTS3. FTS4 non è supportato in Android prima dell'API versione 11. Potresti (1) solo fornire funzionalità di ricerca per API> = 11 o (2) utilizzare una tabella FTS3 (ma questo significa che il database sarà più grande perché la colonna di testo completo esiste in entrambi i database).
popolare le tabelle
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.')");
(Anche in questo caso, ci sono modi migliori di fare inserti che con execSQL
. Sto solo usando per la sua leggibilità.)
Se si è tentato di fare un La query FTS ora su fts_example_table
non otterrebbe risultati. Il motivo è che cambiando una tabella non cambia automaticamente l'altra tabella. È necessario aggiornare manualmente la tabella FTS:
db.execSQL("INSERT INTO fts_example_table (docid, text_column) SELECT _id, text_column FROM example_table");
(. Il docid
è come il rowid
per una tabella regolare) Bisogna fare in modo di aggiornare la tabella FTS (in modo che possa aggiornare l'indice) ogni volta si apporta una modifica (INSERT, DELETE, UPDATE) alla tabella dei contenuti esterni. Questo può diventare ingombrante. Se si sta solo creando un database prepopolato, è possibile effettuare
db.execSQL("INSERT INTO fts_example_table(fts_example_table) VALUES('rebuild')");
che ricostruirà l'intera tabella. Questo può essere lento, quindi, non è qualcosa che vuoi fare dopo ogni piccolo cambiamento. Lo faresti dopo aver terminato tutti gli inserimenti nella tabella dei contenuti esterni. Se è necessario mantenere i database sincronizzati automaticamente, è possibile utilizzare triggers. Go here e scorri un po 'per trovare le direzioni.
query dei database
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_example_table WHERE fts_example_table MATCH ?", selectionArgs);
Questa è la stessa di prima, ma questa volta si ha accesso solo a text_column
(e docid
). Che cosa succede se è necessario ottenere dati da altre colonne nella tabella dei contenuti esterni? Poiché lo docid
della tabella FTS corrisponde allo rowid
(e in questo caso _id
) della tabella del contenuto esterno, è possibile utilizzare un join. (Grazie a this answer per l'aiuto.)
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);
Letture
passare attraverso questi documenti con attenzione per vedere altri modi di utilizzare FTS tavoli virtuali:
Note aggiuntive
- Gli operatori di set (AND, OR, NOT) nelle query FTS di SQLite hanno Standard Query Syntax e Enhanced Query Syntax. Sfortunatamente, Android non supporta la sintassi avanzata delle query (vedi here, here, here e here). Ciò significa che la combinazione di AND e OR diventa difficile (richiede l'uso di
UNION
o il controllo di PRAGMA compile_options
sembra). Davvero sfortunato. Si prega di aggiungere un commento se c'è un aggiornamento in quest'area.
domanda ben documentato, sto contrastare la downvote arbitraria sei arrivato qui. – Mekap