一 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形式存储的。
两种索引实际存储数据的情况
如果是读数据,是没有问题的。都能在业务中拿到一个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的时候有问题