Estou tendo dificuldade em entender como usar a pesquisa de texto completo (FTS) com o Android. Eu li a documentação do SQLite sobre as extensões FTS3 e FTS4 . E eu sei que é possível fazer no Android . No entanto, estou tendo dificuldade em encontrar exemplos que possa compreender.
O modelo básico de banco de dados
Uma tabela de banco de dados SQLite (nomeada example_table
) possui 4 colunas. No entanto, há apenas uma coluna (nomeada text_column
) que precisa ser indexada para uma pesquisa de texto completo. Cada linha de text_column
contém texto que varia em comprimento de 0 a 1000 palavras. O número total de linhas é maior que 10.000.
- Como você configuraria a mesa e / ou a mesa virtual FTS?
- Como você executaria uma consulta FTS no
text_column
?
Notas Adicionais:
- Como apenas uma coluna precisa ser indexada, apenas usar uma tabela FTS (e descartá-la
example_table
) seria ineficiente para consultas não FTS . - Para uma tabela tão grande, o armazenamento de entradas duplicadas
text_column
na tabela FTS seria indesejável. Esta postagem sugere o uso de uma tabela de conteúdo externo . - As tabelas de conteúdo externo usam FTS4, mas FTS4 não é compatível antes da API 11 do Android . Uma resposta pode assumir uma API> = 11, mas comentar sobre as opções de suporte a versões anteriores pode ser útil.
- Alterar dados na tabela original não atualiza automaticamente a tabela FTS (e vice-versa). Incluir acionadores em sua resposta não é necessário para este exemplo básico, mas seria útil mesmo assim.
android
sqlite
full-text-search
Suragch
fonte
fonte
Respostas:
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 suaSQLiteOpenHelper
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
é comorowid
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 fazerdb.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
(edocid
). E se você precisar obter dados de outras colunas na tabela de conteúdo externo? Visto que odocid
da tabela FTS corresponde aorowid
(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
UNION
ou a verificação, aoPRAGMA compile_options
que parece). Muito infeliz. Adicione um comentário se houver alguma atualização nesta área.fonte
Não se esqueça de quando usar o conteúdo de para reconstruir a mesa fts.
Eu faço isso com um gatilho em atualizar, inserir, excluir
fonte
INSERT INTO foo_fts VALUES("rebuild")