【问题标题】:Elasticsearch - query exact value in array so that documents containing that value+others are not returnedElasticsearch - 查询数组中的确切值,以便不返回包含该值+其他的文档
【发布时间】:2018-11-23 07:21:13
【问题描述】:

我正在尝试创建一个查询来搜索一个值,该值将只返回具有该确切值的文档(即使在数组中重复)而不返回其他文档(即使在大批)。因此,"bar" : [ "A", "A"] 符合条件,但 "bar" : [ "A", "B"] 不符合条件

数据集示例:

"loren" : [
  {
    "id" : "1", 
    "foo": [{"bar": "A"},{"bar": "A"}]
  },
  {
    "id" : "2", 
    "foo": [{"bar": "A"},{"bar": "B"}]
  },
]

我期望的输出示例:

"hits": {
    "total": 1,
    "max_score": 0.3666863,
    "hits": [
        {
            "_index": "loren",
            "_type": "loren",
            "_id": "2",
            "_score": 0.3666863,
            "_source": {
                "foo": [
                    {
                        "bar": "A"
                    },
                    {
                        "bar": "A"
                    }
                ]
            }
        }
    ]
}

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    您可以使用下面的Script Query 来查找您要查找的内容。

    请注意,bar 字段的类型应为 keyword

    POST <your_search_index>/_search
    {
      "query": {
            "bool" : {
                "filter" : {
                    "script" : {
                        "script" : {
                            "source" : """
                              List myList = doc['bar'];
                              int size = myList.size();
                              int count = Collections.frequency(myList,params.token);
                              if(count==size)
                                return true;
                              """,
                            "lang"   : "painless",
                            "params": {
                              "token": "test"
                            }
                        }
                    }
                }
            }
        }
    }
    

    您将在响应中得到文档列表,其中包含字段 bar 仅具有 test 作为其值。

    请注意,如果您的映射是动态创建的,您可以在上述查询中尝试使用bar.keyword

    如果有帮助请告诉我!

    【讨论】:

    • 感谢您的帮助,我已经尝试过这种方法,但没有按预期工作。另外我认为直接使用查询会有更好的性能。这是使用 oracle (sqlfiddle.com/#!4/dd338/5) 的数据集和查询示例。问题是我没有足够的关于弹性搜索的知识来转换那个例子,你能帮忙吗?
    • 当然,但是请您发布您在结果中观察到的内容以及您的期望。查看您的问题,上述查询可以正常工作。同时我会检查链接。
    • @bsferreira 您提到的链接有多个连接,这在 ES 中不起作用。您能否发布您的映射详细信息,您的索引是什么样的,我可能可以根据您的映射详细信息创建一个查询,类似于您提到的链接。
    • @bsferreira 嘿,我在那个链接中。对不起,我之前有一些工作。看到我在该链接中发送的消息后,请告诉我。
    【解决方案2】:

    @Kamal 感谢您的启发。这让我得到了我认为的答案……但请告诉我你的想法。

    过滤数组时,看起来像通过执行doc['foo.bar'].size();,elasticsearch 生成count(distinct ...) sql-equivalent 并为具有n 不同值的数组返回大小n

    工作查询示例:

    GET /loren/_search 
    {
       "_source":[
          "foo.bar"
       ],
       "query":{
          "bool":{
             "must":[
                {
                   "match":{
                      "foo.bar":"A"
                   }
                }
             ],
             "filter":{
                "script":{
                   "script":{
                      "source":"1==doc['foo.bar'].size();",
                      "lang":"painless"
                   }
                }
             }
          }
       }
    }
    

    【讨论】:

    • 是的,没错。我想知道为什么我的解决方案不能在您的机器上运行Bummer :(。经过我们的讨论,我尝试过的解决方案仍然按预期工作。 :( 请注意,我的解决方案会检查名为 test 的单词。如果您查看它,它会检查我在params.token 中传递的单词test。您是否将此值 test 更改为 SMTDU 并试一试。我确信它会按预期工作。
    • { "source" : """ List myList = doc['functions.brandCode.keyword']; int size = myList.size(); int count = Collections.frequency(myList,params.token); if(count==size) return true; """, "lang" : "painless", "params": { "token": "SMT" } }
    • 无论如何,您的解决方案看起来不错:-)。继续接受它,但如果你还没有,请支持我的答案;-)。如果您仍有任何疑问,请告诉我。
    • 我尝试了您的解决方案,甚至对其进行了一些小调整,但没有按预期工作。我赞成您的回答,因为它实际上有很大帮助。谢谢你,你真好!
    • 好吧,最后,我很高兴你得到了解决方案!! :)
    猜你喜欢
    • 2017-01-26
    • 2015-08-03
    • 1970-01-01
    • 1970-01-01
    • 2016-09-05
    • 2021-06-12
    • 2021-10-02
    • 2014-12-16
    • 1970-01-01
    相关资源
    最近更新 更多