【问题标题】:Elasticsearch Fuzzy PhrasesElasticsearch 模糊短语
【发布时间】:2019-08-29 19:07:04
【问题描述】:

我有以下查询来为我的搜索添加模糊性。但是,我现在意识到 match 查询不像 match_phrase 那样考虑搜索字符串中单词的顺序。但是,我无法让 match_phrase 给我模糊的结果。有没有办法让 match 考虑单词之间的顺序和距离?

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

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    最终发现我需要使用span 查询的组合,这可以很好地调整模糊性和杂乱性。我需要添加一个函数来手动标记我的短语并以编程方式添加到“子句”数组中:

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

    【讨论】:

    • 感谢您的回复,它对我有用,但我想我应该提一下 content 应该替换为您要搜索的 field_name。例如,如果您要搜索 title 字段,则将 "content": {"fuziness": "2", "value": "word"} 替换为 "title": {"fuziness": "2", "value": "word"}
    • 我希望 elasticsearch 有一种方法来标记短语,然后将它们传递到这个 span_near 子句中。有办法吗?
    • @GNG 可能你可以在此之前提出一个额外的请求elastic.co/guide/en/elasticsearch/reference/current/…。然后使用 span_near 以编程方式构建请求。
    【解决方案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 成为可选的?
    【解决方案3】:

    确实,一个很好的问答。 我很惊讶这种“模糊短语匹配”没有开箱即用的支持。

    这是一个经过测试的 NodeJS 代码,它在多搜索 (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;
    };
    

    【讨论】:

    • 如何让span_multi 成为可选的?
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2019-05-08
      • 1970-01-01
      • 1970-01-01
      • 2011-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多