Resposta mais básica
Estou usando o sql simples abaixo para que tudo seja o mais claro e legível possível. Em seu projeto, você pode usar os métodos de conveniência Android. O db
objeto usado a seguir é uma instância de SQLiteDatabase .
Criar Tabela FTS
db.execSQL("CREATE VIRTUAL TABLE fts_table USING fts3 ( col_1, col_2, text_column )");
Isso poderia ir no onCreate()
método de sua SQLiteOpenHelper
classe estendida .
Preencher a Tabela 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.')");
Seria melhor usar SQLiteDatabase # insert ou instruções preparadas do que execSQL
.
Consultar Tabela FTS
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_table WHERE fts_table MATCH ?", selectionArgs);
Você também pode usar o método de consulta SQLiteDatabase # . Observe a MATCH
palavra - chave.
Resposta mais completa
A tabela FTS virtual acima tem um problema com isso. Cada coluna é indexada, mas isso é um desperdício de espaço e recursos se algumas colunas não precisam ser indexadas. A única coluna que precisa de um índice FTS é provavelmente o text_column
.
Para resolver este problema, usaremos uma combinação de uma mesa regular e uma mesa FTS virtual. A tabela FTS conterá o índice, mas nenhum dos dados reais da tabela regular. Em vez disso, ele terá um link para o conteúdo da tabela regular. Isso é chamado de tabela de conteúdo externo .
Crie as tabelas
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)");
Observe que temos que usar FTS4 para fazer isso em vez de FTS3. FTS4 não é compatível com Android antes da API versão 11. Você poderia (1) fornecer funcionalidade de pesquisa apenas para API> = 11 ou (2) usar uma tabela FTS3 (mas isso significa que o banco de dados será maior porque a coluna de texto completo existe em ambas as bases de dados).
Preencher as tabelas
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.')");
(Novamente, há maneiras melhores de fazer inserções do que com execSQL
. Estou apenas usando para sua legibilidade.)
Se você tentasse fazer uma consulta FTS agora fts_example_table
, não obteria resultados. O motivo é que alterar uma tabela não altera automaticamente a outra. Você deve atualizar manualmente a tabela FTS:
db.execSQL("INSERT INTO fts_example_table (docid, text_column) SELECT _id, text_column FROM example_table");
(O docid
é como rowid
para uma tabela regular.) Você deve certificar-se de atualizar a tabela FTS (para que ela possa atualizar o índice) toda vez que fizer uma alteração (INSERT, DELETE, UPDATE) na tabela de conteúdo externo. Isso pode ser complicado. Se você está fazendo apenas um banco de dados pré-preenchido, você pode fazer
db.execSQL("INSERT INTO fts_example_table(fts_example_table) VALUES('rebuild')");
que irá reconstruir toda a tabela. Isso pode ser lento, portanto, não é algo que você queira fazer após cada pequena mudança. Você faria isso depois de terminar todas as inserções na tabela de conteúdo externo. Se você precisa manter os bancos de dados em sincronia automaticamente, você pode usar gatilhos . Vá aqui e role um pouco para baixo para encontrar as direções.
Consultar os bancos de dados
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_example_table WHERE fts_example_table MATCH ?", selectionArgs);
Este é o mesmo de antes, exceto que desta vez você só tem acesso a text_column
(e docid
). E se você precisar obter dados de outras colunas na tabela de conteúdo externo? Visto que o docid
da tabela FTS corresponde ao rowid
(e neste caso _id
) da tabela de conteúdo externo, você pode usar uma junção. (Obrigado a esta resposta pela ajuda com isso.)
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);
Leitura Adicional
Leia estes documentos cuidadosamente para ver outras maneiras de usar tabelas virtuais FTS:
Notas Adicionais