ES使用技巧和踩坑记录

一  es使tips

可用postman直接import

1  查看索引结构:

curl --location --request GET 'http://127.0.0.1:4343/index_name/'

2  查看某个索引的索引数量(ps:浏览器插件显示的数量是不准的)

curl --location --request GET 'http://127.0.0.1:4343/index_name/_count'

3  简单条件搜索es数据

curl --location --request POST 'http://127.0.0.1:4343/index_name/_search' \
--header 'Content-Type: application/json' \
--data-raw '{
    "query": {
       "match":{
           "id":5521
       }
    }
}'

4  nested嵌套结构查询

curl --location --request POST 'http://http//127.0.0.1:4343/index_name/_search?pretty' \
--header 'Content-Type: application/json' \
--data-raw '{
    "query": {
        "bool": {
            "must": [
                {
                    "nested": {
                        "path": "nested_obj",
                        "query": {
                            "bool": {
                                "must": [
                                    {
                                        "range": {
                                            "nested_obj.date": {
                                                "from": null,
                                                "to": "2021-01",
                                                "include_lower": true,
                                                "include_upper": true,
                                                "boost": 1.0
                                            }
                                        }
                                    },
                                    {
                                        "range": {
                                            "nested_obj.date": {
                                                "from": "2021-09",
                                                "to": null,
                                                "include_lower": true,
                                                "include_upper": true,
                                                "boost": 1.0
                                            }
                                        }
                                    }
                                ]
                            }
                        }
                    }
                }
            ]
        }
    }
}'

5  (根据doc_id)更新索引数据

curl --location --request POST 'http://127.0.0.1:4343/index_name/_update/427' \
--header 'Content-Type: application/json' \
--data-raw '{
    "doc": {
        "pipeline_deposit_time": [],
        "pipeline_id": 100,
        "pipeline_status": 1,
        "pipeline_deposit": [
            {
                "date": "",
                "amount": 40000,
                "budget_date_day_start": "2021-09-01",
                "budget_date_day_end": "2021-09-07"
            },
            {
                "date": "",
                "amount": 50000,
                "budget_date_day_start": "2021-09-11",
                "budget_date_day_end": "2021-09-17"
            }
        ],
        "pipeline_name": "测试"
    }
}'

6  根据条件删除索引数据(慎用)

curl --location --request POST 'http://127.0.0.1:4343/index_name/_delete_by_query' \
--header 'Content-Type: application/json' \
--data-raw '{
    "query": {
        "match": {
            "pipeline_id": 100
        }
    }
}'

7  复杂的条件查询(多个条件或nested查询看下官方文档和博客)

二  es踩坑记录

1  在筛选多个时间段交集的时候不能用obj,要用nested嵌套的obj搜索才准确。

我们先来看下nested索引结构和普通结构的区别

{
    "index_name": {
        "aliases": {},
        "mappings": {
            "dynamic": "false",
            "properties": {
                "create_time": {
                    "type": "date",
                    "format": "yyyy-MM-dd HH:mm:ss"
                },
                "id": {
                    "type": "long"
                },
                "pipeline_deposit": {
                    "properties": {
                        "amount": {
                            "type": "long"
                        },
                        "budget_date_day_end": {
                            "type": "date",
                            "format": "yyyy-MM-dd"
                        },
                        "budget_date_day_start": {
                            "type": "date",
                            "format": "yyyy-MM-dd"
                        },
                        "date": {
                            "type": "text"
                        }
                    }
                },
                "pipeline_deposit_time": {
                    "type": "date",
                    "format": "yyyy-MM"
                }
            }
        }
    }
}

// 含有nested结构的索引
{
    "index_name_v1": {
        "aliases": {},
        "mappings": {
            "dynamic": "false",
            "properties": {
                "create_time": {
                    "type": "date",
                    "format": "yyyy-MM-dd HH:mm:ss"
                },
                "creator_id": {
                    "type": "long"
                },
                "pipeline_deposit": {
                    // 注意这里多了个【type:nested】 !!!
                    "type": "nested",
                    "properties": {
                        "amount": {
                            "type": "long"
                        },
                        "budget_date_day_end": {
                            "type": "date",
                            "format": "yyyy-MM-dd"
                        },
                        "budget_date_day_start": {
                            "type": "date",
                            "format": "yyyy-MM-dd"
                        },
                        "date": {
                            "type": "text"
                        }
                    }
                },
                "pipeline_deposit_time": {
                    "type": "date",
                    "format": "yyyy-MM"
                }
            }
        }
    }
}

现在我们的需求是筛选的时间范围和es中的【 budget_date_day_start,budget_date_day_end】有交集

比如我们es中的有一个doc是这种数据

{
    "_index": "index_name",
    "_type": "_doc",
    "_id": "100",
    "_score": 1.0,
    "_source": {
        "pipeline_deposit": [
            {
                "date": "",
                "amount": 40000,
                "budget_date_day_start": "2021-09-01",
                "budget_date_day_end": "2021-09-07"
            },
            {
                "date": "",
                "amount": 50000,
                "budget_date_day_start": "2021-09-11",
                "budget_date_day_end": "2021-09-17"
            }
        ],
        "creator_id": 2935151
    }
},

圈重点!!!

如果筛选范围是【2021-09-08 - 2021-09-10】在index索引内是可以筛选出来这个doc的(这是不符合预期的,因为没有和任意一个obj有交集),在index_name_v1(nested结构的索引)是不能筛选出来这个doc的(是符合预期的)

问题原因:

es中的doc都是以map形式存储的。

两种索引实际存储数据的情况

ES使用技巧和踩坑记录

 如果是读数据,是没有问题的。都能在业务中拿到一个obj的list。如果要对两个字段进行gte lte筛选,则必须使用index_name_v1结构的索引。

【 budget_date_day_start,budget_date_day_end】有交集筛选的filter会形成【budget_date_day_start.lte(parm2), budget_date_day_end.gte(parm1)】

{
    "query": {
        "bool": {
            "must": [
                {
                    "nested": {
                        "path": "pipeline_deposit",
                        "query": {
                            "bool": {
                                "must": [
                                    {
                                        "range": {
                                            "pipeline_deposit.budget_date_day_start": {
                                                "from": null,
                                                "to": "2021-01",
                                                "include_lower": true,
                                                "include_upper": true,
                                                "boost": 1.0
                                            }
                                        }
                                    },
                                    {
                                        "range": {
                                            "pipeline_deposit.budget_date_day_end": {
                                                "from": "2021-09",
                                                "to": null,
                                                "include_lower": true,
                                                "include_upper": true,
                                                "boost": 1.0
                                            }
                                        }
                                    }
                                ]
                            }
                        }
                    }
                }
            ]
        }
    }
}

利用nested查询最终形成的filter是正确的

{
    "path": "pipeline_deposit",
    "query": {
        "bool": {
            "must": [
                {
                    "range": {
                        "pipeline_deposit.budget_date_day_start": {
                            "from": null,
                            "to": "2021-01",
                            "include_lower": true,
                            "include_upper": true,
                            "boost": 1.0
                        }
                    }
                },
                {
                    "range": {
                        "pipeline_deposit.budget_date_day_end": {
                            "from": "2021-09",
                            "to": null,
                            "include_lower": true,
                            "include_upper": true,
                            "boost": 1.0
                        }
                    }
                }
            ]
        }
    }
}

上面没有nested查询最终形成的filter,是不正确的,因为es中把obj打平存储(导致搜索范围变大,取开始的最小和结束的最大) 上面两条数据的可以检索出的范围就变成了【 2021-09-01,2021-09-17】而不是【 2021-09-01,2021-09-07】&& 【 2021-09-11,2021-09-17】。

2  es中存储了意料之外的数据

比如我们要存储的es的数据的esDto是这样的

import lombok.Data;

@Data
public class TestEsDTO {

    private Long param1;

    private String param2;

    @Override
    public String getparam3() {
        return String.valueOf(this.param1);
    }
}

然后我们最后http调用es存储的时候是这样用的(这个json是fastjson)

    private void buildDoc(UpdateRequest updateRequest, UpdateCommonParam param) {
        return updateRequest.doc(JSON.toJSONStringWithDateFormat(param.getObj(), param.getDateFormat(), SerializerFeature.WriteDateUseDateFormat),
                                 XContentType.JSON);
    }

这样做的话会在es中生成一个意外的数据param3,实际上我们只想在es中存储param1和param2的值。

原因:Gson是通过反射遍历该类中的所有属性,并把其值序列化成json字符串;JackJson和fastJson是通过getter方法获取属性,并把其值序列化成json字符串

解决办法:esDto中不要有get..(get开头的方法),采用Gson或者构建map的方式构建doc,再执行更新操作。

3  更新es异常,构建doc的时候有问题

ES使用技巧和踩坑记录

 

上一篇:10018. 津津的储蓄计划


下一篇:python数据分析--人员变动情况分析