我有以下指数:
+-----+-----+-------+
| oid | tag | value |
+-----+-----+-------+
| 1 | t1 | aaa |
| 1 | t2 | bbb |
| 2 | t1 | aaa |
| 2 | t2 | ddd |
| 2 | t3 | eee |
+-----+-----+-------+
其中:类-对象ID,标记-属性名,值-属性值。
映射:
"mappings": {
"document": {
"_all": { "enabled": false },
"properties": {
"oid": { "type": "integer" },
"tag": { "type": "text" }
"value": { "type": "text" },
}
}
}
这个简单的结构允许存储任意数量的对象属性,通过一个属性或多个使用or逻辑运算符进行搜索是相当简单的。例如,获取对象,对象在哪里:
(tag='t1' AND value='aaa') OR (tag='t2' AND value='ddd')
ES查询:
{
"_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操作符将两个子查询连接到两个不同的记录。例如,获取对象,对象在哪里:
(tag='t1' AND value='aaa') AND (tag='t2' AND value='ddd')
在这种情况下,结果必须是:{ "oid":"2“}
搜索数据包含在两个不同的记录中,在这种情况下,应用必须而不是从前面的示例中返回任何内容。
我在SQL中有两个等价于我所需要的东西:
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
发布于 2018-04-16 06:37:38
为了实现您想要的结果,您需要使用嵌套类型,即映射应该如下所示:
PUT my-index
{
"mappings": {
"doc": {
"properties": {
"oid": {
"type": "keyword"
},
"data": {
"type": "nested",
"properties": {
"tag": {
"type": "keyword"
},
"value": {
"type": "text"
}
}
}
}
}
}
}
这些文件的索引如下:
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"}] }
然后,您可以使您的查询工作如下:
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"
}
}
]
}
}
}
}
]
}
}
}
发布于 2018-04-20 06:42:36
可能有一种方法,这有点难看:将术语汇总添加到查询体中。
{
"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"
}
}
}
}
如果一切顺利,这将输出类似于
{
"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的”键“。
然而,应该有更好的办法。如果你想改变你的映射到一个类似样式的文档,即。把所有的字段都存储在一个文档中,生活就会轻松得多。
{
"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样式的查询。
https://stackoverflow.com/questions/49814486
复制相似问题