
最近生产Elasticsearch中用到嵌套类型,同时还发现一些小坑,跟大家做个简单的分享。
关于ES中的嵌套类型:
- 官方释义:nested类型是object一种数据类型,允许对象数组以互相独立的方式进行索引
- 适用场景:字段值为复杂类型的情况
案例演示:
数据准备
PUT /test_index/_doc/1
{
“column_1”: “A”,
“column_2”: “B”,
“column_list”: [
{
“list_1”: “aa”,
“list_2”: 1
},
{
“list_1”: “bb”,
“list_2”: 2
},
{
“list_1”: “cc”,
“list_2”: 3
}
]
}
PUT /test_index/_doc/2
{
“column_1”: “A”,
“column_2”: “B”,
“column_list”: [
{
“list_1”: “a”,
“list_2”: 11
},
{
“list_1”: “b”,
“list_2”: 22
},
{
“list_1”: “c”,
“list_2”: 33
}
]
}
假设现在有个需求,要查询test索引中list_1=“aa” 并且 list_2=3的数据。
先预期一下结果,应该没有返回数据才对。
写DSL并查看结果
GET test_index/_search
{
“query”: {
“bool”: {
“must”: [
{
“match”: {
“column_list.list_1”: “aa”
}
},
{
“match”: {
“column_list.list_2”: 3
}
}
]
}
}
}
结果惊为天人,居然把“_doc/1”这条数据查出来了。
查阅资料后原因如下:
当字段值为复杂数据类型(Object、Geo-Point等)的时候,ES内部实际是以如下方式保存数据的
{
“column_1”: “A”,
“column_2”: “B”,
“column_list.list_1”: [“aa”,“bb”,“cc”],
“column_list.list_2”: [1,2,3]
}
通俗的讲就是ES没有保存对象中的逻辑关系,从而导致无法准确搜索。
解决方案:
使用Nested类型
1、创建Mapping
PUT test_index
{
“mappings”: {
“properties”: {
“column_1” :{“type”: “string”},
“column_2” :{“type”: “string”},
“column_list”: {
“type”: “nested”,
“properties”: {
“list_1”: {
“type”: “text”
},
“list_2”: {
“type”: “long”
},
}
}
}
}
}
2、写入数据(同上)
3、相同的查询条件,使用新的查询语句
GET /test/_search
{
“query”: {
“nested”: {
“path”: “column_list”,
“query”: {
“bool”: {
“must”: [
{
“match”: {
“column_list.list_1”: “aa”
}
},
{
“match”: {
“column_list.list_2”: 3
}
}
]
}
}
}
}
}
此时查询结果为理想值,空。
所以遇到对象中多个数组间有逻辑关系时,我们需要使用Nested类型
但是Nested还是有他的弊端
在压测中发现,普通的query查询效率远远高于使用nested查询的效率,特别是nested中存在多个对象时。
所以在业务设计时如果存在此类场景也可以将nested部分单独出一个索引进行使用,从而避免使用nested而引起的查询性能问题。




