【问题标题】:Elasticsearch match only and exactly given tags in tags arrayElasticsearch 仅匹配标签数组中给定的标签
【发布时间】:2021-02-05 19:15:23
【问题描述】:

例如,有四个文档

{id: 1, tags :["cat", "dog", "horse"]}
{id: 2, tags :["dog", "cat"]}
{id: 3, tags :["cat"]}
{id: 4, tags :["dog"]}
  1. 如果我用["cat"] 查询标签,我应该只会得到{id: 3, tags :["cat"]}

  2. 如果我用["dog"] 查询标签,我应该只会得到{id: 4, tags :["dog"]}

如何构造这样的查询?

【问题讨论】:

    标签: elasticsearch elasticsearch-query


    【解决方案1】:

    Elasticsearch 评分算法为具有确切搜索词的文档提供最高分,即在您的情况下为 cat,并且由于您只需要完全包含 cat 的文档,您可以使用具有 1 值的 size 参数,这样,您的结果会更快,因为脚本在搜索期间遍历每个文档时速度很慢。

    添加工作示例。

    索引示例文档

    POST /index/_doc/1

    {
        "id": 1,
        "tags": [
            "cat",
            "dog",
            "horse"
        ]
    }
    

    文档 2

    {
        "id": 2,
        "tags": [
            "dog",
            "cat"
        ]
    }
    

    文档 3

    {
        "id": 3,
        "tags": [
            "cat"
        ]
    }
    

    文档 4

    {
        "id": 4,
        "tags": [
            "dog"
        ]
    }
    

    搜索查询

    {
        "size": 1, // Note
        "query": {
            "bool": {
                "must": [
                    {
                        "term": {
                            "tags": {
                                "value": "cat"
                            }
                        }
                    }
                ]
            }
        }    
    }
    

    返回搜索结果

    "hits": [
                {
                    "_index": "66069294",
                    "_type": "_doc",
                    "_id": "3",
                    "_score": 0.43250346,
                    "_source": {
                        "id": 3,
                        "tags": [
                            "cat" // Note
                        ]
                    }
                }
            ]
    

    【讨论】:

    • 我认为 size 只返回一个文档,但是有多个文档只包含 'cat'
    • @ecka 哦,是的,您可以增加 size 参数并解析响应,并且结果按分数的 desc 顺序排序,一旦您获得包含超过 1 个项目的结果,你可以忽略其他结果 :) 仍然比在 ES 端编写脚本要快得多
    • @ecka 如果您可以提出后续问题,那就太好了,否则如果您可以投票并接受答案,TIA 那就太好了 :)
    • 我认为这两个答案似乎都是一种解决方法。如果有一个数组并在 ElasticSearch 中找到它的等价物,那就太好了。拥有数组的精确匹配会很棒。不过在 mongodb 中很容易做到。两个答案都不能回答我的问题,如果我找到解决方案,我会接受
    • 我按照你的建议做了
    【解决方案2】:

    [更新]:更新了适用于 5.x 和 7.x 的答案。


    您可以为tags 添加长度过滤器以及term 查询。请参阅下面使用相关数据提供的示例。

    对于高于 5.x 的版本(在 7.x 上测试),这需要以特定方式为索引创建映射(如下所述)。

    1. tags 中的type 设置为keyword

       PUT /my-index/_mapping
       {"properties":{"id":{"type":"integer"},"tags":{"type":"keyword"}}}
      
    2. tagstype设置为text,并为tags启用fieldata

       PUT /my-index/_mapping
       {"properties":{"id":{"type":"integer"},"tags":{"type":"text","fielddata":true}}}
      

    5.x 不需要这种严格的映射。

    映射后,索引文档:

    PUT /_bulk
    {"create": {"_index": "my-index", "_id": 1}}
    {"id": 1, "tags" :["cat", "dog", "horse"]}
    {"create": {"_index": "my-index", "_id": 2}}
    {"id": 2, "tags" :["cat", "dog"]}
    {"create": {"_index": "my-index", "_id": 3}}
    {"id": 3, "tags" :["cat"]}
    {"create": {"_index": "my-index", "_id": 4}}
    {"id": 4, "tags" :["dog"]}
    

    现在搜索索引文档:

    GET my-index/_search
    {
      "query": {
        "bool": {
          "must": [
            {
              "term": {
                "tags": {
                  "value": "cat"
                }
              }
            },
            {
              "script": {
                "script": "doc['tags'].length == 1"
              }
            }
          ]
        }
      }
    }
    

    结果应该返回预期的文档。

    重要提示:以上步骤适用于 5.x,但有一个变化:您需要在操作 because you can have more than one document types (and mappings) in one index in ES 5.x 中提供文档类型 (_type)。

    【讨论】:

    • 这个查询你测试了吗,它返回: "Text fields are not optimised for operations that require per-document field data like aggregations and sorting, so these operations are disabled by default. Please use a keyword field instead. Alternatively, set fielddata=true on [tags] in order to load field data by uninverting the inverted index. Note that this can use significant memory."异常。
    • 我在 ES 5.x 上测试过查询。您可能在 7.x 上运行了此查询。
    猜你喜欢
    • 2016-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-02
    • 2021-12-20
    • 2020-12-14
    • 1970-01-01
    • 2010-12-14
    相关资源
    最近更新 更多