【问题标题】:Find exact two words anywhere in sentence (array of sentences) elastcsearch 6.8在句子(句子数组)中的任何位置找到确切的两个单词 elastcsearch 6.8
【发布时间】:2019-10-08 08:54:45
【问题描述】:

我正在尝试为 elasticsearch 编写一个自定义原始查询,其中我需要通过包含多个由空格分隔的 ID 的字符串中的 ID 组合进行搜索。

搜索字段如下所示:

文档 1

"sentence": [
             "1060 1764 1769 1770 1772 2807 2808 3570", 
             "1101 3402 3403",
             "1101 1764 1769 1770 1772",
             "1001 1060 1099 1100 1101 2806 2807 2808 3570"
            ]

文档 2

"sentence": [
             "1060 2806 2807 2808 3570", 
             "1101 3402 3403",
             "1101 1764 1769 1770 1772",
             "1001 1060 1488 1489 1490 2806 2807 2808 3570"
            ]

例如,当使用参数“1060 和 1101”进行搜索时,它应该只返回文档 1,因为它在单个字符串中包含这两个值。 尽可能避免使用嵌套查询。

尝试使用 bool 必须匹配查询、匹配短语查询、查询字符串、简单查询字符串、bool 必须匹配过滤词查询、正则表达式组合。 一切都返回了一些东西,但不完全是我需要的。

【问题讨论】:

  • 请分享您的映射。你的映射可以改变吗?要实现您想做的事情,您必须使用嵌套字段。
  • 这是字段的映射 ``` "sentence": { "type": "text", "fields": { "keyword": { "type": "keyword", " ignore_above": 256 } } }, ``` 我猜他们可以为那个属性改变,是否可以只改变那个属性的映射?
  • 要更新映射,您必须重新索引数据

标签: json elasticsearch elasticsearch-query elasticsearch-6.8


【解决方案1】:

问题的根源在于您并不真正了解数组如何在弹性中工作,来自docs

没有专用的数组数据类型。

意思是当您索引一个数组(未键入 nested)时,由于弹性“扁平化”数组这一事实,您将无法查询其中的单个项目。

你有两个选择:

  1. 更合适的解决方案是重新索引数据,输入要输入的句子nested,然后您可以单独查询每个项目。

新结构将如下所示:

            {
                "mappings": {
                    "doc": {
                        "properties": {
                            "sentence": {
                                "type": "nested",
                                "properties": {
                                    "value": {
                                        "type": "text"
                                    }
                                }
                            }
                        }
                    }
                }
            }

但是,由于我不熟悉您的产品和需求,因此该解决方案可能不适合您,因为这可能会影响您已经处理的许多其他查询。

因此选项编号 2.使用scripting过滤掉文档:

(这个脚本是我快速编写的一个示例,您可以编写一个更高效的版本来优化运行时,假设许多文档不会包含您查询的任何这些术语,添加query 将是有效的(类似于你一直在做)在 filter 操作之前迭代“可疑”匹配。)

{
        "query": {
            "bool": {
                 // the must is optional and only here to filter out documents that are not relevant, you should test this on your data to see if its needed.
                 "must": {"query_string": {"default_field": "sentence", "query": "1060 AND 1101"}},
                "filter": {
                    "script": {
                        "script": {
                            "lang": "painless",
                            "source": `                     
                                boolean matched = false;
                                String[] queries = new String[] {'1060', '1101'};
                                for (int i = 0; i < doc['sentence.keyword'].length; i++) {
                                    int count = 0;
                                    for (int j = 0; j < queries.length; j++) {
                                        if (doc['sentence.keyword'][i].indexOf(queries[j]) > -1) {
                                            count += 1;
                                        }
                                    }
                                    if (count === queries.length) {
                                        matched = true;
                                    }
                                }
                                return matched
                                `
                        }
                    }
                }

            }
        }
    }

正如我之前所说,选项 2 是不太“合适”的解决方案,而且效率要低得多。但如果需要,它是一个有效的。

【讨论】:

    【解决方案2】:

    1) 使用此映射为您的字段重新索引您的数据。嵌套字段(数组)的每个元素都是一个句子。由于您只使用数字列表,我会将它们存储为字符串,升级可能是使用自定义分析器以确保索引(但如果您继续使用简单整数,则不是强制性的)

    "sentence": {
        "type": "nested",
            "properties": {
                "sentencearray": {
                    "type": "text"
                }
            }
        }
    

    2) 使用嵌套查询进行查询

    {
      "query": {
        "nested": {
          "path": "sentence",
          "query": {
            "bool": {
              "must": [
                { "match": { "sentence.sentencearray": "1060" }},
                { "match": { "sentence.sentencearray":  "1101" }} 
              ]
            }
          }
        }
      }
    }
    

    3) 过滤结果,只保留匹配的嵌套元素,在查询中添加inner_hist:

    {
      "query": {
        "nested": {
          "path": "yourfield",
          "query": {
            "bool": {
              "must": [
                { "match": { "yourfield.yourarray": "1012" }},
                { "match": { "yourfield.yourarray":  "1024" }} 
              ]
            }
          },
          "inner_hits":{}
        }
      }
    }
    

    【讨论】:

      【解决方案3】:

      您不需要嵌套数组。这是一个使用短语匹配的工作示例(和一个大问题!)

      # no special mapping needed
      PUT stackoverflow-58283078
      
      POST stackoverflow-58283078/_doc
      {
        "sentence": [
                   "1060 1764 1769 1770 1772 2807 2808 3570", 
                   "1101 3402 3403",
                   "1101 1764 1769 1770 1772",
                   "1001 1060 1099 1100 1101 2806 2807 2808 3570"
                  ]
      }
      
      
      POST stackoverflow-58283078/_doc
      {
        "sentence": [
          "1060 2806 2807 2808 3570",
          "1101 3402 3403",
          "1101 1764 1769 1770 1772",
          "1001 1060 1488 1489 1490 2806 2807 2808 3570"
        ]
      }
      
      POST stackoverflow-58283078/_search
      {
        "query": {
          "match_phrase": {
            "sentence": {
              "query":  "1060 1101",
              "slop": 20
            }
          }
        }
      }
      

      此查询返回:

      {
        "took" : 0,
        "timed_out" : false,
        "_shards" : {
          "total" : 1,
          "successful" : 1,
          "skipped" : 0,
          "failed" : 0
        },
        "hits" : {
          "total" : {
            "value" : 1,
            "relation" : "eq"
          },
          "max_score" : 0.16809675,
          "hits" : [
            {
              "_index" : "stackoverflow-58283078",
              "_type" : "_doc",
              "_id" : "4bsgrG0BWf1JU_OTT9FV",
              "_score" : 0.16809675,
              "_source" : {
                "sentence" : [
                  "1060 1764 1769 1770 1772 2807 2808 3570",
                  "1101 3402 3403",
                  "1101 1764 1769 1770 1772",
                  "1001 1060 1099 1100 1101 2806 2807 2808 3570"
                ]
              }
            }
          ]
        }
      }
      

      为什么?因为短语匹配在令牌的“倾斜”半径内搜索令牌。由于默认的“position_increment_gap”是 100,它在不同的值之间不匹配。

      你有一个句子中的最大标记数吗?例如,如果您想处理 5000 个令牌,您可以配置 5001 的斜率(以允许第一个和最后一个令牌之间反转,相信我这个:p)和一个 position_increment_gap 优于5002.

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多