Recentemente, comecei a usar o ElasticSearch e não consigo fazer com que ele procure parte de uma palavra.
Exemplo: tenho três documentos do meu couchdb indexados no ElasticSearch:
{
"_id" : "1",
"name" : "John Doeman",
"function" : "Janitor"
}
{
"_id" : "2",
"name" : "Jane Doewoman",
"function" : "Teacher"
}
{
"_id" : "3",
"name" : "Jimmy Jackal",
"function" : "Student"
}
Então agora eu quero procurar todos os documentos que contenham "Doe"
curl http://localhost:9200/my_idx/my_type/_search?q=Doe
Isso não retorna nenhum resultado. Mas se eu procurar
curl http://localhost:9200/my_idx/my_type/_search?q=Doeman
Ele retorna um documento (John Doeman).
Eu tentei definir diferentes analisadores e filtros diferentes como propriedades do meu índice. Eu também tentei usar uma consulta completa (por exemplo:
{
"query": {
"term": {
"name": "Doe"
}
}
}
) Mas nada parece funcionar.
Como posso fazer com que o ElasticSearch encontre John Doeman e Jane Doewoman quando procuro "Doe"?
ATUALIZAR
Tentei usar o tokenizer e o filtro nGram, como Igor propôs, assim:
{
"index": {
"index": "my_idx",
"type": "my_type",
"bulk_size": "100",
"bulk_timeout": "10ms",
"analysis": {
"analyzer": {
"my_analyzer": {
"type": "custom",
"tokenizer": "my_ngram_tokenizer",
"filter": [
"my_ngram_filter"
]
}
},
"filter": {
"my_ngram_filter": {
"type": "nGram",
"min_gram": 1,
"max_gram": 1
}
},
"tokenizer": {
"my_ngram_tokenizer": {
"type": "nGram",
"min_gram": 1,
"max_gram": 1
}
}
}
}
}
O problema que estou tendo agora é que cada consulta retorna TODOS os documentos. Alguma dica? A documentação do ElasticSearch sobre o uso do nGram não é excelente ...
fonte
Respostas:
Também estou usando o nGram. Eu uso o tokenizer padrão e o nGram apenas como um filtro. Aqui está a minha configuração:
Vamos encontrar partes de palavras com até 50 letras. Ajuste o max_gram conforme necessário. Em alemão, as palavras podem ficar muito grandes, então eu defino um valor alto.
fonte
A pesquisa com curingas iniciais e finais será extremamente lenta em um índice grande. Se você deseja pesquisar por prefixo de palavra, remova o curinga principal. Se você realmente precisar encontrar uma substring no meio de uma palavra, seria melhor usar o ngram tokenizer.
fonte
Eu acho que não há necessidade de alterar nenhum mapeamento. Tente usar query_string , é perfeito. Todos os cenários funcionarão com o analisador padrão padrão:
Temos dados:
Cenário 1:
Resposta:
Cenário 2:
Resposta:
Cenário 3:
Resposta:
EDIT - mesma implementação com pesquisa elástica de dados da mola https://stackoverflow.com/a/43579948/2357869
Mais uma explicação de como query_string é melhor que outros https://stackoverflow.com/a/43321606/2357869
fonte
sem alterar seus mapeamentos de índice, você poderia fazer uma consulta de prefixo simples que fará pesquisas parciais como você espera
ie
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-query.html
fonte
Experimente a solução com está descrita aqui: Pesquisas exatas de substring no ElasticSearch
Para resolver o problema de uso do disco e o problema do termo de pesquisa muito longo, são usados ngrams com 8 caracteres e comprimento (configurados com: "max_gram": 8 ). Para pesquisar termos com mais de 8 caracteres, transforme sua pesquisa em uma consulta AND booleana, procurando por cada substring de 8 caracteres distinto nessa sequência. Por exemplo, se um usuário pesquisasse um quintal grande (uma sequência de 10 caracteres), a pesquisa seria:
"arge ya E arge yar E rge yard .
fonte
min_gram
emax_gram
parece que seria linearmente dependente do tamanho dos valores de campo ea gama demin
emax
. Quão desaprovado está usando algo assim?ngram
um filtro em um tokenizer? poderia não apenas tê-lo como um tokenizer e, em seguida, aplicar um filtro de minúsculas ...index_ngram: { type: "custom", tokenizer: "ngram_tokenizer", filter: [ "lowercase" ] }
Eu tentei e parece dar os mesmos resultados usando a API de teste analisadorSe você deseja implementar a funcionalidade de preenchimento automático, o Completion Suggester é a solução mais interessante. A próxima postagem no blog contém uma descrição muito clara de como isso funciona.
Em duas palavras, é uma estrutura de dados na memória chamada FST que contém sugestões válidas e é otimizada para recuperação rápida e uso de memória. Essencialmente, é apenas um gráfico. Por exemplo, e FST contendo as palavras
hotel
,marriot
,mercure
,munchen
emunich
ficaria assim:fonte
você pode usar regexp.
se você usar esta consulta:
você fornecerá todos os dados cujo nome começa com "J". Considere que deseja receber apenas os dois primeiros registros que terminam com "man" para que você possa usar esta consulta:
e se você deseja receber todos os registros que existem em seu nome "m", você pode usar esta consulta:
Isso funciona para mim. E espero que minha resposta seja adequada para resolver seu problema.
fonte
O uso de wilcards (*) impede o cálculo de uma pontuação
fonte
Estou usando isso e trabalhei
fonte
Deixa pra lá.
Eu tive que olhar para a documentação do Lucene. Parece que eu posso usar curingas! :-)
faz o truque!
fonte