当前位置: 首页 > 知识库问答 >
问题:

在Elasticsearch中按数组元素匹配

屈升
2023-03-14

我必须在Elasticsearch中构造一个非常重要的查询(现在看来是这样)。假设我有两个实体,每个实体都有一个数组元素,由字符串组成:

1). ['A', 'B']
2). ['A', 'C']
3). ['A', 'E']
4). ['A']

数组元素的映射如下(使用动态模板):

{
  "my_array_of_strings": {
    "path_match": "stringArray*",
    "mapping": {
      "type": "string",
      "index": "not_analyzed"
    }
  }
}

实体的Json表示如下:

{
  "stringArray": [
    "A",
    "B"
  ]
}

然后我有了用户输入:['A','B','C']。

我想要实现的是找到只包含输入中指定元素的实体——预期结果是:[A'、[B']、[A'、[C']、[A'],但不是['A'、[E'](因为用户输入中不存在“E”)。

这个场景可以用Elasticsearch实现吗?

更新:除了使用脚本的解决方案之外——脚本应该可以很好地工作,但很可能会在有许多记录匹配的情况下大大降低查询速度——我还设计了另一个脚本。下面,我将尝试解释它的主要思想,而不是代码实现。

我没有提到的一个重要条件(这可能会给其他用户提供有价值的提示)是数组由枚举元素组成,即数组中此类元素的数量有限。这允许将此类数组展平为实体的单独字段。

假设有5个可能的值:“A”、“B”、“C”、“D”、“E”。这些值中的每一个都是一个布尔字段——如果它为空(即数组版本将包含此元素)则为true,否则为false。然后每个实体都可以重写如下:

1).
A = true
B = true
C = false
D = false
E = false

2).
A = true
B = false
C = true
D = false
E = false

3).
A = true
B = false
C = false
D = false
E = true

4).
A = true
B = false
C = false
D = false
E = false

当用户输入['A','B','C']时,我需要做的就是:A)取所有可能的值(['A','B','C','D','E']),并从中减去用户输入-

这将如预期的那样给出记录1、2和4。我仍在试验这种方法的代码实现,但到目前为止,它看起来很有希望。它还需要测试,但我认为这可能比在查询中使用脚本执行得更快,对资源的要求也更低。

为了进一步优化这一点,可能根本不提供“false”字段,并将之前的查询修改为“D=不存在和E=不存在”-结果应该是相同的。

共有2个答案

红朝
2023-03-14

在同样的情况下,我做了以下步骤:

首先,我删除了索引,用sense plugin重新定义analyzer/settings

DELETE my_index

然后我为my_index定义了自定义分析器

PUT my_index
{
  "index" : {
    "analysis" : {
        "tokenizer" : {
            "comma" : {
                "type" : "pattern",
                "pattern" : ","
            }
        },
        "analyzer" : {
            "comma" : {
                "type" : "custom",
                "tokenizer" : "comma"
            }
        }
    }
  }
}

然后,我在代码中定义了映射属性,但您也可以使用sense来实现这一点。他们两个都一样。

PUT /my_index/_mapping/my_type
{
        "properties" : {
            "conduct_days" : {
                "type" : "string",
                "analyzer" : "comma"
            }
        }
}

然后进行以下测试步骤:

PUT /my_index/my_type/1
{
    "coduct_days" : "1,2,3"
}

PUT /my_index/my_type/2
{
    "conduct_days" : "3,4"
}

PUT /my_index/my_type/3
{
    "conduct_days" : "1,6"
}

GET /my_index/_search
{
    "query": {"match_all": {}}
}

GET /my_index/_search
{
    "filter": {
       "or" : [
          { 
            "term": {
               "coduct_days": "6"
            }
          },
          {
            "term": {
               "coduct_days": "3"
            }
          }
       ]
    }
}
邓德厚
2023-03-14

您可以通过脚本实现这一点,这就是它的外观

{
  "query": {
    "filtered": {
      "filter": {
        "bool": {
          "must": [
            {
              "terms": {
                "name": [
                  "A",
                  "B",
                  "C"
                ]
              }
            },
            {
              "script": {
                "script": "if(user_input.containsAll(doc['name'].values)){return true;}",
                "params": {
                  "user_input": [
                    "A",
                    "B",
                    "C"
                  ]
                }
              }
            }
          ]
        }
      }
    }
  }
}

这个groovy脚本正在检查列表是否包含除['A',B',C']之外的任何内容,如果包含,则返回false,因此它不会返回['A',E']。它只是检查子列表是否匹配。这个脚本可能需要几秒钟。您需要启用动态脚本,而且ES 2的语法可能不同。x,如果不起作用,请告诉我。

编辑1

我只把这两个条件都放在过滤器中。首先只返回包含A、B或C的文档,然后脚本只应用于这些文档,所以这将比前一个更快。更多关于过滤器排序的信息

希望这有帮助!!

 类似资料:
  • 问题内容: 假设我有以下代码: 我可以手动调用下一个函数多次,以使2个数组按“相同名称”分组。 问题是我不知道变量值,在这种情况下为“ dinner”和“ lunch”,因此我想按名称自动对这个statEvents数组进行分组,所以当名称不同时,我会得到尽可能多的数组。 我该怎么办? 问题答案: 从Swift 4开始,此功能已添加到标准库中。您可以这样使用它: 斯威夫特3: 不幸的是,上面的函数复

  • 问题内容: 我想做一个相当复杂的查询/聚合。我看不到该怎么做,因为我刚刚开始使用ES。我的文档看起来像这样: 现在,我想为每个关键字计算property_1可以具有的几个可能值中有多少个。也就是说,我需要一个具有以下响应的存储桶聚合: 如果需要映射,您还可以指定哪个吗?我没有任何非默认映射,我只是将所有内容都转储在那里。 编辑:通过在此处发布上一个示例的批量PUT为您节省了麻烦 编辑2: 我只是试

  • 我试图检索一个带有特定'_ID'的文档和一个带有另一个特定'_ID'的嵌入文档。 我的文档是一个目录,它包含一个课程数组。 示例数据: 在mongod中,我运行这个聚合查询,并得到我想要的结果: 正如我前面提到的,我已经得到了一个目录实例,里面有一个课程实例。

  • 我面临的问题是,我有两个文档,每个文档都包含一个对象数组。我喜欢搜索一个包含嵌套对象两个属性的文档(在同一对象中同时匹配这两个属性),但我总是同时得到这两个文档。 我用以下内容创建了文档: 我为它们定义了一个索引,以防止ES像这样平整对象: 现在,我想使用以下查询搜索第一个文档(): 这应该只返回一个同时匹配两个条件的元素。 不幸的是,它总是返回两个文档。我想这是因为在某个时候,ES仍然会将嵌套对

  • 问题内容: 给定n个元素的数组,即 我可以编写一个扩展,以便可以修改数组以实现以下输出: 有没有一种方法可以实现将数组移动任何索引(正数或负数)的功能。我可以使用子句以命令式方式实现此功能,但我正在寻找的是功能性实现。 该算法很简单: 通过提供的索引将数组分为两个 将第一个数组附加到第二个数组的末尾 有什么方法可以以功能样式实现它吗? 我完成的代码: 问题答案: 您可以使用远程下标并连接结果。这将

  • 我只想在数组中的第一个元素上搜索对象,而忽略其余的元素。例如,对于下面的数据,如果我只想在中搜索数组中的第一个元素。 我知道我可以这样做一个嵌套查询,但这里的问题是所有的车辆都被搜索。我只希望车辆列表中的第0个元素被搜索,其余的被忽略。 理想情况下,我需要类似这样的东西来每次搜索列表中的第一辆车。有什么方法可以有效地做到这一点吗?