ElasticSearch-Поиск Человеческих Имен
у меня есть большая база данных имен, в основном из Шотландии. В настоящее время мы производим прототип для замены существующего программного обеспечения, которое выполняет поиск. Это все еще в производстве, и мы стремимся получить наши результаты как можно ближе к текущим результатам того же поиска.
Я надеялся, что кто-то может мне помочь, я вхожу в поиск в эластичном поиске, запрос "Майкл Хини", я получаю некоторые дикие результаты. Текущий поиск возвращает две основные фамилии, это - "Heaney" и "Heavey" все с именем "Майкл", я могу получить результаты "Heaney" в эластичном поиске, однако я не могу получить "Heavey", и ES также возвращает людей без фамилии "Майкл", однако я ценю, что это связано с тем, что это часть нечеткого запроса. Я знаю, что это узкий случай использования, так как это только один поиск, но получение этого результата и знание того, как я могу его получить, будет помощь.
спасибо.
картография
{
"jr": {
"_all": {
"enabled": true,
"index_analyzer": "index_analyzer",
"search_analyzer": "search_analyzer"
},
"properties": {
"pty_forename": {
"type": "string",
"index": "analyzed",
"boost": 2,
"index_analyzer": "index_analyzer",
"search_analyzer": "search_analyzer",
"store": "yes"
},
"pty_full_name": {
"type": "string",
"index": "analyzed",
"boost": 4,
"index_analyzer": "index_analyzer",
"search_analyzer": "search_analyzer",
"store": "yes"
},
"pty_surname": {
"type": "string",
"index": "analyzed",
"boost": 4,
"index_analyzer": "index_analyzer",
"search_analyzer": "search_analyzer",
"store": "yes"
}
}
}
}'
Настройки Индекс
{
"settings": {
"number_of_shards": 2,
"number_of_replicas": 0,
"analysis": {
"analyzer": {
"index_analyzer": {
"tokenizer": "standard",
"filter": [
"standard",
"my_delimiter",
"lowercase",
"stop",
"asciifolding",
"porter_stem",
"my_metaphone"
]
},
"search_analyzer": {
"tokenizer": "standard",
"filter": [
"standard",
"my_metaphone",
"synonym",
"lowercase",
"stop",
"asciifolding",
"porter_stem"
]
}
},
"filter": {
"synonym": {
"type": "synonym",
"synonyms_path": "synonyms/synonyms.txt"
},
"my_delimiter": {
"type": "word_delimiter",
"generate_word_parts": true,
"catenate_words": false,
"catenate_numbers": false,
"catenate_all": false,
"split_on_case_change": false,
"preserve_original": false,
"split_on_numerics": false,
"stem_english_possessive": false
},
"my_metaphone": {
"type": "phonetic",
"encoder": "metaphone",
"replace": false
}
}
}
}
}'
Fuzzy
{
"from":0, "size":100,
"query": {
"bool": {
"should": [
{
"fuzzy": {
"pty_surname": {
"min_similarity": 0.2,
"value": "Heaney",
"prefix_length": 0,
"boost": 5
}
}
},
{
"fuzzy": {
"pty_forename": {
"min_similarity": 1,
"value": "Michael",
"prefix_length": 0,
"boost": 1
}
}
}
]
}
}
}
1 ответов
во-первых, я воссоздал вашу текущую конфигурацию в игре:https://www.found.no/play/gist/867785a709b4869c5543
если вы идете туда, перейдите на вкладку"Анализ", чтобы увидеть, как текст преобразуется:
обратите внимание, например, что Heaney
заканчивается как [hn, heanei]
С search_analyzer
и [HN, heanei]
С index_analyzer
. Примечание в случае-разница для метафон-термин. Таким образом, это не соответствует.
на fuzzy
запрос не сделайте анализ текста времени запроса. Таким образом, вы в конечном итоге сравнивая Heavey
С heanei
. Это Дамерау-Левенштейна расстояние дольше, чем позволяют ваши параметры.
то, что вы действительно хотите сделать, это использовать нечеткую функциональность match
. Матч тут сделайте анализ текста времени запроса и имеет нечеткости-параметр.
что касается fuzziness
, это немного изменилось в Lucene 4. Раньше он обычно указывался как float. Теперь это должно быть указано как допустимое расстояние. Есть выдающийся запрос на вытягивание, чтобы уточнить, что:https://github.com/elasticsearch/elasticsearch/pull/4332/files
причина, по которой вы получаете людей без имени Michael
это то, что вы делаете bool.should
. Это имеет OR-семантику. Достаточно того, что один матч, но забивать лучше, чем больше матчей.
наконец, объединение всей этой фильтрации в один и тот же термин не обязательно лучший подход. Например, вы не можете знать и повышать точность написания. То, что вы должны рассмотреть, используя multi_field обрабатывать поле в много путей.
вот пример, который вы можете играть с, с командами curl, чтобы воссоздать его ниже. Однако я бы пропустил использование" porter " stemmer полностью для этого. Я сохранил его, чтобы показать, как работает multi_field. Использование комбинации match, match с нечеткостью и фонетическим соответствием ты далеко пойдешь. (Убедитесь, что вы не позволяете нечеткость, когда вы делаете фонетическое соответствие - или вы получите бесполезно нечеткое соответствие. :-)
#!/bin/bash
export ELASTICSEARCH_ENDPOINT="http://localhost:9200"
# Create indexes
curl -XPUT "$ELASTICSEARCH_ENDPOINT/play" -d '{
"settings": {
"analysis": {
"text": [
"Michael",
"Heaney",
"Heavey"
],
"analyzer": {
"metaphone": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"my_metaphone"
]
},
"porter": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"porter_stem"
]
}
},
"filter": {
"my_metaphone": {
"encoder": "metaphone",
"replace": false,
"type": "phonetic"
}
}
}
},
"mappings": {
"jr": {
"properties": {
"pty_surename": {
"type": "multi_field",
"fields": {
"pty_surename": {
"type": "string",
"analyzer": "simple"
},
"metaphone": {
"type": "string",
"analyzer": "metaphone"
},
"porter": {
"type": "string",
"analyzer": "porter"
}
}
}
}
}
}
}'
# Index documents
curl -XPOST "$ELASTICSEARCH_ENDPOINT/_bulk?refresh=true" -d '
{"index":{"_index":"play","_type":"jr"}}
{"pty_surname":"Heaney"}
{"index":{"_index":"play","_type":"jr"}}
{"pty_surname":"Heavey"}
'
# Do searches
curl -XPOST "$ELASTICSEARCH_ENDPOINT/_search?pretty" -d '
{
"query": {
"bool": {
"should": [
{
"bool": {
"should": [
{
"match": {
"pty_surname": {
"query": "heavey"
}
}
},
{
"match": {
"pty_surname": {
"query": "heavey",
"fuzziness": 1
}
}
},
{
"match": {
"pty_surename.metaphone": {
"query": "heavey"
}
}
},
{
"match": {
"pty_surename.porter": {
"query": "heavey"
}
}
}
]
}
}
]
}
}
}
'