Come cercare una parte di una parola con ElasticSearch

Recentemente ho iniziato a utilizzare ElasticSearch e non riesco a farlo cercare una parte di una parola.

Esempio: ho tre documenti dal mio couchdb indicizzato in ElasticSearch:

{ "_id" : "1", "name" : "John Doeman", "function" : "Janitor" } { "_id" : "2", "name" : "Jane Doewoman", "function" : "Teacher" } { "_id" : "3", "name" : "Jimmy Jackal", "function" : "Student" } 

Quindi ora voglio cercare tutti i documenti contenenti “Doe”

 curl http://localhost:9200/my_idx/my_type/_search?q=Doe 

Questo non restituisce alcun colpo. Ma se cerco

 curl http://localhost:9200/my_idx/my_type/_search?q=Doeman 

Restituisce un documento (John Doeman).

Ho provato a impostare diversi analizzatori e filtri diversi come proprietà del mio indice. Ho anche provato a utilizzare un’interrogazione completa (ad esempio:

 { "query": { "term": { "name": "Doe" } } } 

) Ma niente sembra funzionare.

Come posso fare in modo che ElasticSearch trovi sia John Doeman che Jane Doewoman quando cerco “Doe”?

AGGIORNARE

Ho provato ad usare il tokenizer e il filtro nGram, come proposto da Igor, in questo modo:

 { "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 } } } } } 

Il problema che sto avendo ora è che ogni singola query restituisce TUTTI i documenti. Qualche indicazione? La documentazione di ElasticSearch sull’uso di nGram non è eccezionale …

Sto usando anche nGram. Io uso tokenizer standard e nGram solo come filtro. Ecco la mia configurazione:

 { "index": { "index": "my_idx", "type": "my_type", "analysis": { "index_analyzer": { "my_index_analyzer": { "type": "custom", "tokenizer": "standard", "filter": [ "lowercase", "mynGram" ] } }, "search_analyzer": { "my_search_analyzer": { "type": "custom", "tokenizer": "standard", "filter": [ "standard", "lowercase", "mynGram" ] } }, "filter": { "mynGram": { "type": "nGram", "min_gram": 2, "max_gram": 50 } } } } } 

Troviamo parti di parole fino a 50 lettere. Regola il max_gram di cui hai bisogno. In tedesco le parole possono diventare davvero grandi, quindi l’ho impostato su un valore elevato.

La ricerca con caratteri jolly iniziali e finali sarà estremamente lenta su un indice di grandi dimensioni. Se vuoi essere in grado di cercare per parola prefisso, rimuovi il carattere jolly principale. Se hai davvero bisogno di trovare una sottostringa nel mezzo di una parola, è meglio usare il tokenizer ngram.

Penso che non sia necessario modificare alcuna mapping. Prova a usare query_string , è perfetto. Tutti gli scenari funzioneranno con l’analizzatore standard di default:

Abbiamo dati:

 {"_id" : "1","name" : "John Doeman","function" : "Janitor"} {"_id" : "2","name" : "Jane Doewoman","function" : "Teacher"} 

Scenario 1:

 {"query": { "query_string" : {"default_field" : "name", "query" : "*Doe*"} } } 

Risposta:

 {"_id" : "1","name" : "John Doeman","function" : "Janitor"} {"_id" : "2","name" : "Jane Doewoman","function" : "Teacher"} 

Scenario 2:

 {"query": { "query_string" : {"default_field" : "name", "query" : "*Jan*"} } } 

Risposta:

 {"_id" : "1","name" : "John Doeman","function" : "Janitor"} 

Scenario 3:

 {"query": { "query_string" : {"default_field" : "name", "query" : "*oh* *oe*"} } } 

Risposta:

 {"_id" : "1","name" : "John Doeman","function" : "Janitor"} {"_id" : "2","name" : "Jane Doewoman","function" : "Teacher"} 

MODIFICA – Stessa implementazione con la ricerca elastica dei dati primaverili https://stackoverflow.com/a/43579948/2357869

Un’altra spiegazione su come query_string è migliore di altre https://stackoverflow.com/a/43321606/2357869

senza modificare le mappature degli indici potresti fare una semplice query prefissata che farà ricerche parziali come speri

vale a dire.

 { "query": { "prefix" : { "name" : "Doe" } } } 

https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-query.html

Prova la soluzione con è descritto qui: Ricerche di sottostringa esatta in ElasticSearch

 { "mappings": { "my_type": { "index_analyzer":"index_ngram", "search_analyzer":"search_ngram" } }, "settings": { "analysis": { "filter": { "ngram_filter": { "type": "ngram", "min_gram": 3, "max_gram": 8 } }, "analyzer": { "index_ngram": { "type": "custom", "tokenizer": "keyword", "filter": [ "ngram_filter", "lowercase" ] }, "search_ngram": { "type": "custom", "tokenizer": "keyword", "filter": "lowercase" } } } } } 

Per risolvere il problema di utilizzo del disco e il problema di ricerca troppo lungo vengono utilizzati brevi ngram di 8 caratteri (configurati con: “max_gram”: 8 ). Per cercare termini con più di 8 caratteri, trasforma la ricerca in una query AND booleana cercando ogni sottostringa distinta di 8 caratteri in quella stringa. Ad esempio, se un utente ha cercato un piazzale di grandi dimensioni (una stringa di 10 caratteri), la ricerca sarebbe:

“arge ya AND arge yar E rge yard .

Se si desidera implementare la funzionalità di completamento automatico, Completion Suggester è la soluzione più accurata. Il prossimo post sul blog contiene una descrizione molto chiara di come funziona.

In due parole, si tratta di una struttura di dati in memoria denominata FST che contiene suggerimenti validi ed è ottimizzata per il recupero e l’utilizzo della memoria. Essenzialmente, è solo un grafico. Ad esempio, e FST contenente le parole hotel , marriot , mercure , munchen e munich sarebbe simile a questo:

inserisci la descrizione dell'immagine qui

Elasticsearch ha una query con caratteri jolly che può essere utilizzata in questo caso ed è la più semplice. Restituirà entrambi i documenti di corrispondenza

puoi usare regexp.

 { "_id" : "1", "name" : "John Doeman" , "function" : "Janitor"} { "_id" : "2", "name" : "Jane Doewoman","function" : "Teacher" } { "_id" : "3", "name" : "Jimmy Jackal" ,"function" : "Student" } 

se usi questa query:

 { "query": { "regexp": { "name": "J.*" } } } 

fornirai tutti i dati che il loro nome inizia con “J”. Si desidera ricevere solo i primi due record in cui il loro nome termina con “man” in modo da poter utilizzare questa query:

 { "query": { "regexp": { "name": ".*man" } } } 

e se vuoi ricevere tutti i record che nel loro nome esistono “m”, puoi usare questa query:

 { "query": { "regexp": { "name": ".*m.*" } } } 

Questo funziona per me. E spero che la mia risposta sia adatta a risolvere il tuo problema.

Non importa.

Dovevo dare un’occhiata alla documentazione di Lucene. Sembra che io possa usare i caratteri jolly! 🙂

 curl http://localhost:9200/my_idx/my_type/_search?q=*Doe* 

fa il trucco!