Нечеткие фразы Elasticsearch
У меня есть следующий запрос, чтобы добавить нечеткость в мой поиск. Однако теперь я понимаю, что запрос соответствия не учитывает порядок слов в строке поиска, как это делает match_phrase. Однако я не могу получить match_phrase, чтобы дать мне результаты с нечеткостью. Есть ли способ сказать совпадение, чтобы рассмотреть порядок и расстояние между словами?
{
"query": {
"match": {
"content": {
"query": "some search terms like this",
"fuzziness": 1,
"operator": "and"
}
}
}
}
Ответы
Ответ 1
В конце концов выяснилось, что мне нужно использовать комбинацию span
запросов, которые дают отличную тонкую настройку для нечеткости и slop. Мне нужно было добавить функцию, чтобы вручную токенизировать мои фразы и добавлять к массиву "clauses" программным образом:
{"query":
{
"span_near": {
"clauses": [
{
"span_multi": {
"match": {
"fuzzy": {
"content": {
"fuzziness": "2",
"value": "word"
}
}
}
}
},
{
"span_multi": {
"match": {
"fuzzy": {
"content": {
"fuzziness": "2",
"value": "another"
}
}
}
}
}
],
"slop": 1,
"in_order": "true"
Ответ 2
@econgineer Отличная почта.
Я хотел попробовать это для ES-запроса, над которым мы работаем, но я слишком ленив, чтобы продолжать делать данные JSON....
Я думаю, что этот код работает... странно это заставляет jq жаловаться, но ElasticSearch работает....
import json
import pprint
from collections import defaultdict
nested_dict = lambda: defaultdict(nested_dict)
query=nested_dict()
query['span_near']['clauses']=list()
query['slop']='1'
query['in_order']="true"
words=['what','is','this']
for w in words:
nest = nested_dict()
nest["span_multi"]["match"]["fuzzy"]["msg"]["fuzziness"]["value"]=w
nest["span_multi"]["match"]["fuzzy"]["msg"]["fuzziness"]["fuzziness"]="2"
json.dumps(nest)
query['span_near']['clauses'].append(json.loads(json.dumps(nest)))
pprint.pprint(json.loads(json.dumps(query)))
Если вы украшаете вывод
cat t2.json | tr "\'" "\"" | jq '.'
Вы должны увидеть что-то вроде
{
"in_order": "true",
"slop": "1",
"span_near": {
"clauses": [
{
"span_multi": {
"match": {
"fuzzy": {
"msg": {
"fuzziness": {
"fuzziness": "2",
"value": "what"
}
}
}
}
}
},
{
"span_multi": {
"match": {
"fuzzy": {
"msg": {
"fuzziness": {
"fuzziness": "2",
"value": "is"
}
}
}
}
}
},
{
"span_multi": {
"match": {
"fuzzy": {
"msg": {
"fuzziness": {
"fuzziness": "2",
"value": "this"
}
}
}
}
}
}
]
}
}
И затем для запроса ES это обычный нормальный
curl --silent My_ES_Server:9200:/INDEX/_search -d @t2.json
Большое спасибо за начальное руководство, я надеюсь, что кто-то найдет это полезным.
Ответ 3
Действительно, отличный вопрос и ответ.
Я удивлен, что это "нечеткое совпадение фразы" не имеет поддержки из коробки.
Здесь протестированный код NodeJS, который генерирует блок запросов с нечеткой фразой (multi clause), в контексте многопользовательского поиска (msearch), но это должно работать одинаково с одним поиском.
Применение:
let queryBody = [];
client.msearch({
body: queryBody
})
queryBody.push({ index: 'YOUR_INDEX' });
queryBody.push(createESFuzzyPhraseQueryBlock('YOUR PHRASE', 'YOUR_FIELD_NAME', 2)); // 2 <- fuzziness
Функции:
const createESFuzzyPhraseClauseBlock = (word, esFieldName, fuzziness) => {
let clauseBlock = JSON.parse(
`{
"span_multi": {
"match": {
"fuzzy": {
"${esFieldName}": {
"fuzziness": "${fuzziness}",
"value": "${word}"
}
}
}
}
}`);
return clauseBlock;
};
const createESFuzzyPhraseQueryBlock = (phrase, esFieldName, fuzziness) => {
let clauses = [];
let words = phrase.split(' ');
words.forEach(word => clauses.push(createESFuzzyPhraseClauseBlock(word, esFieldName, fuzziness)));
let queryBlock =
{
"query":
{
"span_near": {
"clauses": clauses,
"slop": 1,
"in_order": "true"
}
}
};
return queryBlock;
};
Ответ 4
Также рассмотрите возможность смешивания запросов, для меня базовый запрос выглядел так: для фраз длины 2 я использовал префиксный запрос, а для остальных я использовал запрос на совпадение с fuziness, установленным в AUTO.