Elasticsearch模糊短语匹配

16

我有以下的搜索查询想要添加模糊匹配。但是,我现在意识到match查询不考虑搜索字符串中单词的顺序,而match_phrase则会考虑。然而,我无法让match_phrase使用模糊匹配来返回结果。有没有一种方法可以告诉match同时考虑单词之间的顺序和距离呢?

{
    "query": {
        "match": {
            "content": {
                "query": "some search terms like this",
                "fuzziness": 1,
                "operator": "and"
            }
        }
    }
}
4个回答

23
最终我发现需要使用span查询的组合来微调模糊度和误差。我需要添加一个函数手动标记短语并以编程方式将其添加到"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
谢谢您的回复,这对我很有帮助。但是我认为我应该提到content应该替换为您想要搜索的field_name。例如,如果您想要搜索title字段,则将"content": {"fuziness": "2", "value": "word"}替换为"title": {"fuziness": "2", "value": "word"} - Dan Lupascu
1
我希望有一种方法可以让elasticsearch对短语进行分词,然后将它们传递到这个span_near子句中。有办法吗? - GNG
@GNG也许你可以在这个请求之前添加一个额外的请求https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-standard-tokenizer.html。然后使用span_near以编程方式构建请求。 - woto

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

非常感谢你提供的初步指导,我希望其他人也能从中受益。

如何使span_multi中的任何一个可选? - perrohunter

1

确实,这是一个很好的问题和答案。

我很惊讶这个“模糊短语匹配”没有默认支持。

以下是一个经过测试的NodeJS代码,它生成了模糊短语匹配(多个子句)查询块,在多搜索(msearch)的上下文中,但在单个搜索中同样有效。

用法:

const queryBody = [
  { index: 'YOUR_INDEX' },
  createESFuzzyPhraseQueryBlock('YOUR PHRASE', 'YOUR_FIELD_NAME', 2)
];

client.msearch({
   body: queryBody
})

函数:

const createESFuzzyPhraseClauseBlock = (word, esFieldName, fuzziness) => {
    const clauseBlock = {
            "span_multi": {
                "match": {
                    "fuzzy": {
                        [esFieldName]: {
                            "fuzziness": fuzziness,
                            "value": word
                        }
                    }
                }
            }
        });

    return clauseBlock;
};


const createESFuzzyPhraseQueryBlock = (phrase, esFieldName, fuzziness) => {
    const clauses = phrase.split(' ').map(word => createESFuzzyPhraseClauseBlock(word, esFieldName, fuzziness));

    const queryBlock =
        {
            "query":
                {
                    "span_near": {
                        "clauses": clauses,
                        "slop": 1,
                        "in_order": "true"
                    }
                }
        };

    return queryBlock;
};

如何使span_multi中的任何一个可选? - perrohunter

0

还可以考虑混合使用查询,对于我来说,基本查询看起来像这样 - 对于长度为2的短语,我使用前缀查询,对于其余部分,我使用模糊匹配查询,并将fuziness设置为AUTO。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接