elasticsearch 针对对象查询问题

2021-11-10 10:35:16 +08:00
 Saxton

现有以下数据:

[
    {
        "title":"Hello Wolrd",
        "desc":"你好世界",
        "customFields":[
            {
                "key":"tags",
                "value":"灌水"
            },
            {
                "key":"test",
                "value":"问候"
            },
        ]
    },
    {
        "title":"Hello Jack",
        "desc":"你好 jack",
        "customFields":[
            {
                "key":"tags",
                "value":"问候"
            }
        ]
    }
]

customFields 属于自定义字段,因为涉及业务需要对自定义字段做筛选,我使用以下查询语法:

{
    "query":{
        "bool":{
            "must":{
                "trem":[
                    {
                        "customFields.key":"tags"
                    },
                    {
                        "customFields.value":"问候"
                    }
                ]
            }
        }
    }
}

预期结果是只返回有问候的 tags ,但实际两条都返回了,这种情况怎么做精准的筛选呢

2187 次点击
所在节点    Elasticsearch
19 条回复
xjngbla
2021-11-10 10:56:39 +08:00
trem 单词写错了,应该是 term
lithium4010
2021-11-10 10:58:38 +08:00
你这里 term 里面是或的关系
sun2920989
2021-11-10 11:02:14 +08:00
不出意外的话,你应该是需要 nested.
Chad0000
2021-11-10 11:05:06 +08:00
如果这个 ES 是转存的,不是原始数据,可能你在转换时存为 object 好点? "customFields": { "tags":"灌水", "test":"问候" }
Saxton
2021-11-10 11:14:19 +08:00
@sun2920989 nested 嵌套关系吗
Saxton
2021-11-10 11:15:16 +08:00
@Chad0000 感谢!
X0ray
2021-11-10 11:16:47 +08:00
{
"query": {
"bool": {
"must": [
{
"term": {
"customFields.key": "tags"
}
},
{
"term": {
"customFields.value": "问候"
}
}
]
}
}
}
Saxton
2021-11-10 11:18:01 +08:00
@Chad0000 被你这么一说思路瞬间通了
sun2920989
2021-11-10 11:20:21 +08:00
@Saxton #5 简单来说,es 的数据结构存储你这样的数据,如果不使用 nested,实际上会被重新打平拆分的,你的数据的第一条实际上会变为 customFields.key:[tags,test], customFields.value:[灌水,问候] ,所以就会被你在筛选 tags + 问候 时也被筛选到.以上信息源自于我的记忆不保证准确,你自行搜索下.
Saxton
2021-11-10 11:22:20 +08:00
@sun2920989 bingo 没错 我刚才阅读了文档 确实是这样 我已经按照楼上那个思路换成 object 方式了 不以数组方式储存了 将字段名作为 obj 的 key 即可 感谢 !
sun2920989
2021-11-10 11:24:16 +08:00
@Saxton #10 嗯,那你需要额外处理下第一条数据那种一对多的关系.
liangzhe
2021-11-10 14:03:45 +08:00
@sun2920989 大佬,请教下如果用户自定义的 tag 极其多,超过了 es 单条文档的字段数量限制应该怎么做?目前遇到了这个问题
sun2920989
2021-11-10 14:15:39 +08:00
@liangzhe #12 不是大佬,客气了.你所指的 tag 极多是在什么层级呢,以楼主主贴的数据结构看,即使 tag 再多,对于 es 来讲也是 customFields.key 这样一个字段,只是字段里的内容比较长而已.es 对整体的字段数量,以及对单一一个字段里面内容的长度,比如 keyword 类型,也是有限制的,但是这些也都可以按照实际情况进行一定的配置来调大一些.主要看你的数据结构了.
wbd31
2021-11-10 17:15:55 +08:00
方案 3 的 object 可以设置为 flattened 类型来避免映射爆炸
https://www.elastic.co/guide/en/elasticsearch/reference/current/flattened.html
sun2920989
2021-11-10 17:39:57 +08:00
不管是 object 还是 nested,或者只是基础的 text, keyword 等等,不管什么类型的数据结构,只要字段总量是确定的,也不用过于担心映射爆炸的问题,映射爆炸主要是对于动态增加的字段来说的,与是否是对象和是否是嵌套无关.比如字段名字叫做 tag1,tag2 这样随着业务不断新增的时候,才会需要考虑这个问题.像我上一楼回复中说的,如果是主楼那样的数据结构,不管有多少个 tag,其实也只有 customFields.key 一个字段而已,字段是数组的话,字段内的数值变多,并不会引起映射爆炸.同样,以上说法也是我记得的情况,可以再找找资料了解一下.
sun2920989
2021-11-10 17:45:26 +08:00
按照追加的说法,将下一层级中需要搜索的字段提出来到上一层级中再存一分,我感觉并不能解决此类问题,比如,主楼第一条数据最终还是会存储为 tag:['tags','test'],因为是一对多的结构.所以一样会被主楼这样的条件所查询到.当然可能这个地方我理解的和楼主实现的方式不一样.
sun2920989
2021-11-10 17:49:12 +08:00
如果说楼主使用的方式是 tags:'灌水' ,test:问候,这样来存储的话,才是真的将一个 tag 变成了一个字段,这样随着 tag 变得越来越多,才需要考虑映射爆炸的问题.因为此时的总映射字段数量是不确定的,是持续动态变多的.
Saxton
2021-11-11 09:28:54 +08:00
@sun2920989 是的,就是这个方式, 其实 tags 这个 key 本身变化由用户决定,所以不会出现被拉成平行的问题,但也伴随着时间的推移自定义的字段会越来越多,目前暂时没想到其他好的解决方案,只能从业务层去限制用户的字段数量
sun2920989
2021-11-11 10:41:45 +08:00
@Saxton #18 好的,了解了.也建议再从业务层上考虑下是否会存在某个 tag 的 key 对应了多个不同的 value 的场景.防止后续出现意外.比如[{key:tags1,value:测试 1},{key:tags1,value:测试 2}],这样的结构.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/814347

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX