【问题标题】:Elasticsearch match query for Multi Word not Exact word多词不精确词的 Elasticsearch 匹配查询
【发布时间】:2020-04-21 01:56:28
【问题描述】:

我是弹性搜索的新手,我厌倦了在索引文档中查找数据。就像我有 4 个文档,并且有 2 个字段 fullName, userName -

{
    "_index": "users",
    "_type": "users",
    "_id": "NwV2GG8BmEFrScbl3IE8",
    "_score": 1,
    "_source": {
        "fullName": "Max Payne",
        "id": 1,
        "userName": "MaxP"
    }
},
{
    "_index": "users",
    "_type": "users",
    "_id": "MgV2GG8BmEFrScbl3IE8",
    "_score": 1,
    "_source": {
        "fullName": "Thomas John",
        "id": 6,
        "userName": "ThomesJ"            
    }
},
{
    "_index": "users",
    "_type": "users",
    "_id": "MgD2TG1BmEFrrfbs3RT9",
    "_score": 1,
    "_source": {
        "fullName": "John well",
        "id": 7,
        "userName": "ThomesW"
    }
},
{
    "_index": "users",
    "_type": "users",
    "_id": "QwR58DTBmEFrScbl8op4",
    "_score": 1,
    "_source": {
        "fullName": "Max smith",
        "id": 1,
        "userName": "MaxS"
    }
}

如果搜索 情况1 'Ma' 那么我需要 3 个文件

案例 2 'Max' 那么我需要 2 个文档

案例 3 'Max s' 然后我需要 1 个文件 (Max smith) 'Max p' 然后我需要 1 个文件(Max Payne)

案例 4 'John' 那么我需要 2 个文件

我试试这个,如果完整的字符串匹配,则找到数据,否则找不到数据。

"bool" : {
    "should": {
        "query_string": {
        "query": '*'+keyword+'*', // "query": keyword+'*',
        "fields": [ "fullName", "userName" ]
        },
    },
}

另外,我尝试了这个但不起作用

"term": {
    "fullName": {
    "value": keyword
  }
}

我在 NodeJs 客户端中使用 Elasticsearch 6.3

【问题讨论】:

    标签: elasticsearch nodes


    【解决方案1】:

    您需要根据您的不同场景尝试此查询并使用通配符,您将获得所需的结果

    {
      "query": {
        "wildcard": {
          "fullName": {
            "value": "keyword"
          }
        }
      }
    }
    

    例如案例1:“value”:“*ma*” 案例2:“value”:“max”等。

    希望这有帮助。

    【讨论】:

    【解决方案2】:

    Elasticsearch 的工作方式与您在这里所期望的完全不同。使用您使用的默认分析器,索引字段中的每个单词都会成为可搜索的标记。

    可以使用 通配符 查询 (https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-wildcard-query.html) 按令牌的一部分进行搜索。但是,强烈建议不要盲目地使用通配符查询,因为它们不能很好地随着索引的增长而扩展。

    如果绝对需要像您描述的那样按令牌的一部分进行搜索,您应该查看 n-gram 令牌过滤器 (https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-ngram-tokenfilter.html)。 这将产生像 [m,a,x,ma,ax] 这样的标记,可以让您搜索“ma”。 下面是一个 ngram-filter 的实现示例:

    PUT so_example
    {
      "settings": {
        "analysis": {
          "analyzer": {
            "ngram-example": {
              "tokenizer": "standard",
              "filter": [
                "ngram"
              ]
            }
          }
        }
      },
      "mappings": {
        "users": {
          "properties": {
            "userName": {
              "type": "text",
              "analyzer": "ngram-example"
            },
            "fullName": {
              "type": "text",
              "analyzer": "ngram-example"
            }
          }
        }
      }
    }
    

    这将允许执行您的搜索,例如:

    GET so_example/_search
    {
      "query": {
        "multi_match": {
          "query": "Max Pa",
          "type": "phrase",
          "fields": [
            "fullName"
          ]
        }
      }
    }
    

    对于您的“Max P”示例,您需要记住您正在搜索 2 个标记,因为它们在技术上是 2 个单词。要搜索需要按给定顺序排列的标记,您需要 phrase_match 查询 (https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query-phrase.html)。否则搜索词 P 不需要在搜索字段中跟随 Max。

    【讨论】:

    • phrase_match 看起来像 var keyword = req.body.search; query = { "match_phrase" : { "fullName" : keyword } },对吧?
    • 鉴于您想要搜索多个字段,您可以将其与 multi_match 查询结合使用。例如: "query": { "multi_match" : { "query": "Max P", "type": "phrase", "fields": [ "fullName", "userName" ] } }
    • 我尝试了您上面的代码但无法正常工作(未找到数据)"query":{ "multi_match": { "query": "max P", "type": "phrase", "fields": [ "fullName", "userName" ] } }
    • 请注意,默认分析器存储字段区分大小写。因此,您的搜索字词需要适应这一点。我的确切示例不匹配,因为“Max”和“P”实际上并不是数据集中的标记。 “MaxP”将匹配或“Max Payne”。对于像“Max Pa”这样的部分匹配,您必须查看 n-gram 过滤器或提到的通配符查询。
    • 那么,我需要对索引进行更改吗?
    【解决方案3】:

    使用一个名为“search_name”的新属性来存储用户名和全名。 'copy_to' 将有助于实现这一目标。

    如下所示更改索引 -

    PUT user_index
    {
      "settings": {
        "number_of_shards": 1,
        "analysis": {
          "filter": {
            "edge_filter": {
              "type": "edge_ngram",
              "min_gram": 1,
              "max_gram": 50
            }
          },
          "analyzer": {
            "lowercase": {
              "type": "custom",
              "tokenizer": "keyword",
              "filter": [
                "trim",
                "lowercase"
              ]
            },
            "userName_analyzer": {
              "type": "custom",
              "tokenizer": "standard",
              "filter": [
                "lowercase",
    
                "edge_filter"
              ]
            },
            "fullName_analyzer": {
              "type": "custom",
              "tokenizer": "standard",
              "filter": [
                "lowercase",
    
                "edge_filter"
              ]
            }
          }
        }
      },
      "mappings": {
        "properties": {
          "userName": {
            "type": "text",
            "analyzer": "userName_analyzer",
            "search_analyzer": "standard",
            "copy_to": "search_name"
          },
          "fullName": {
            "type": "text",
            "analyzer": "fullName_analyzer",
            "search_analyzer": "standard",
            "copy_to": "search_name"
          },
          "search_name":{
            "type": "text",
            "analyzer": "fullName_analyzer",
            "search_analyzer": "standard"
          }
        }
      }
    }
    

    现在使用如下搜索查询 -

    GET user_index/_search
    {
      "query": {
        "bool": {
          "should": [
            {
              "match": {
                "search_name":{
                  "query": "max p",
                  "operator" : "and"
                }
              }
            }
          ]
        }
      }
    }
    

    请根据给定的要求更改查询值。 希望这会有所帮助。

    【讨论】:

    猜你喜欢
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    相关资源
    最近更新 更多