首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >ES6:通过AND运算符将子查询连接到两个不同的行

ES6:通过AND运算符将子查询连接到两个不同的行
EN

Stack Overflow用户
提问于 2018-04-13 10:08:11
回答 2查看 165关注 0票数 0

我有以下指数:

代码语言:javascript
运行
复制
+-----+-----+-------+
| oid | tag | value |
+-----+-----+-------+
|  1  | t1  |  aaa  |
|  1  | t2  |  bbb  |
|  2  | t1  |  aaa  |
|  2  | t2  |  ddd  |
|  2  | t3  |  eee  |
+-----+-----+-------+

其中:-对象ID,标记-属性名,-属性值。

映射:

代码语言:javascript
运行
复制
"mappings": {
    "document": {
        "_all": { "enabled": false },
        "properties": {
            "oid": { "type": "integer" },
            "tag": { "type": "text" }
            "value": { "type": "text" },
        }
    }
}

这个简单的结构允许存储任意数量的对象属性,通过一个属性或多个使用or逻辑运算符进行搜索是相当简单的。例如,获取对象,对象在哪里:

代码语言:javascript
运行
复制
(tag='t1' AND value='aaa') OR (tag='t2' AND value='ddd')

ES查询:

代码语言:javascript
运行
复制
{
  "_source": { "includes":["oid"] },
  "query": {
    "bool": {
      "should": [
        {
          "bool": {
            "must": [
              { "term": { "tag": "t1" } },
              { "term": { "value": "aaa" } }
            ]
          }
        },
        {
          "bool": {
            "must": [
              { "term": { "tag": "t2" } },
              { "term": { "value": "ddd" } }
            ]
          }
        }
      ],
      "minimum_should_match": "1"
    }
  }
}

但是,使用和逻辑运算符搜索两个或多个属性是很困难的。因此,问题是如何通过AND操作符将两个子查询连接到两个不同的记录。例如,获取对象,对象在哪里:

代码语言:javascript
运行
复制
(tag='t1' AND value='aaa') AND (tag='t2' AND value='ddd')

在这种情况下,结果必须是:{ "oid":"2“}

搜索数据包含在两个不同的记录中,在这种情况下,应用必须而不是从前面的示例中返回任何内容。

我在SQL中有两个等价于我所需要的东西:

代码语言:javascript
运行
复制
SELECT i1.[oid]
FROM [index] i1 INNER JOIN [index] i2 ON i1.oid = i2.oid
WHERE
    (i1.tag='t1' AND i1.value='aaa')
    AND
    (i2.tag='t2' AND i2.value='ddd')

---------

SELECT [oid] FROM [index] WHERE tag='t1' AND value='aaa'
INTERSECT   
SELECT [oid] FROM [index] WHERE tag='t2' AND value='ddd'

执行这两个请求并在客户机上合并它们不是选项。

弹性搜索版本为6.1.1

EN

回答 2

Stack Overflow用户

发布于 2018-04-16 06:37:38

为了实现您想要的结果,您需要使用嵌套类型,即映射应该如下所示:

代码语言:javascript
运行
复制
PUT my-index
{
  "mappings": {
    "doc": {
      "properties": {
        "oid": {
          "type": "keyword"
        },
        "data": {
          "type": "nested",
          "properties": {
            "tag": {
              "type": "keyword"
            },
            "value": {
              "type": "text"
            }
          }
        }
      }
    }
  }
}

这些文件的索引如下:

代码语言:javascript
运行
复制
PUT /my-index/doc/_bulk
{ "index": {"_id": 1}}
{ "oid": 1, "data": [ {"tag": "t1", "value": "aaa"}, {"tag": "t2", "value": "bbb"}] }
{ "index": {"_id": 2}}
{ "oid": 2, "data": [ {"tag": "t1", "value": "aaa"}, {"tag": "t2", "value": "ddd"}, {"tag": "t3", "value": "eee"}] }

然后,您可以使您的查询工作如下:

代码语言:javascript
运行
复制
POST my-index/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "nested": {
            "path": "data",
            "query": {
              "bool": {
                "filter": [
                  {
                    "term": {
                      "data.tag": "t1"
                    }
                  },
                  {
                    "term": {
                      "data.value": "aaa"
                    }
                  }
                ]
              }
            }
          }
        },
        {
          "nested": {
            "path": "data",
            "query": {
              "bool": {
                "filter": [
                  {
                    "term": {
                      "data.tag": "t2"
                    }
                  },
                  {
                    "term": {
                      "data.value": "ddd"
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}
票数 1
EN

Stack Overflow用户

发布于 2018-04-20 06:42:36

可能有一种方法,这有点难看:将术语汇总添加到查询体中。

代码语言:javascript
运行
复制
  {
  "query": {
    "bool": {
      "should": [
        {
          "bool": {
            "must": [
              { "term": { "tag": "t1" } },
              { "term": { "value": "aaa" } }
            ]
          }
        },
        {
          "bool": {
            "must": [
              { "term": { "tag": "t2" } },
              { "term": { "value": "ddd" } }
            ]
          }
        }
      ],
      "minimum_should_match": "1"
    }
  },
  "size": 0,
  "aggs": {
      "find_joined_oid": {
          "terms": {
              "field": "oid.keyword"
          }
      }
  }
}

如果一切顺利,这将输出类似于

代码语言:javascript
运行
复制
  {
  "took": 123,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 123,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "find_joined_oid": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "1",
          "doc_count": 1
        },
        {
          "key": "2",
          "doc_count": 2
        }
    }
  }
}

在这里,在“聚合”部分,

“键”:"1“

表示您的"oid":"1",以及

"doc_counts":1

表示查询中有1次命中"oid":"1“。

正如您所查询的要匹配的标记数(例如N ),在聚合结果体中,只有那些带有"doc_count“等于N的”键“才是您正在追求的结果。在本例中,您正在查询标记:t1(值aaa)和标记:t2(值ddd),因此是N=2。您可以在结果桶列表中迭代,找出"doc_count“等于2的”键“。

然而,应该有更好的办法。如果你想改变你的映射到一个类似样式的文档,即。把所有的字段都存储在一个文档中,生活就会轻松得多。

代码语言:javascript
运行
复制
{
    "properties": {
        "oid": { "type": "integer" },
        "tag-1": { "type": "text" }
        "value-1": { "type": "text" },
        "tag-2": { "type": "text" }
        "value-2": { "type": "text" }
    }
}

当您想要添加新的标记值对时,只需获得与you有关的原始文档,将新的标记对放入文档中,并将整个新文档用原来的_id返回到Elasticsearch中。在大多数情况下,动态映射将正常工作,这意味着您不需要显式地断言新字段的映射。

像Elasticsearch之类的非SQL数据库以及其他数据库的设计并不能处理您所要求的这种SQL样式的查询。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49814486

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档