Elasticsearch中使用Runtime Fields

开发 前端
在我们使用es的开发过程中可能会遇到这么一种情况,比如我们的线路名称字段lineName字段在设置mapping的时候使用的是text类型,但是后期发现需要使用这个字段来进行聚合操作,那么我们除了对索引进行reindex操作外,还有什么办法可以解决这个问题呢?

1、背景

在我们使用es的开发过程中可能会遇到这么一种情况,比如我们的线路名称字段lineName字段在设置mapping的时候使用的是text类型,但是后期发现需要使用这个字段来进行聚合操作,那么我们除了对索引进行reindex操作外,还有什么办法可以解决这个问题呢?此处我们通过runtime field来解决。

2、runtime field介绍

2.1 runtime field可以实现的功能

运行时字段是在查询时评估的字段。是在es7.11之后增加的运行时字段使您能够:

  1. 将字段添加到现有文档,而无需重新索引数据
  2. 在不了解数据结构的情况下开始处理数据
  3. 在查询时覆盖从索引字段返回的值
  4. 定义特定用途的字段,而不修改原始mappingruntime field 的作用

2.2 runtime field优缺点

  1. runtime field是运行时增加的字段,不会被索引和存储,不会增加索引的大小。
  2. runtime field 可以像普通字段一样使用,可以进行查询,排序,聚合等操作。
  3. 可以动态的添加字段。
  4. 可以在查询时覆盖字段的值。即fields中和_source中可以返回同名的字段,但是值可能不一样。
  5. 阻止mapping爆炸,可以先使用后定义。
  6. 针对经常被搜索或聚合等操作的字段,不适合使用runtime field,而应该定义在mapping中。
  7. runtime field不会出现在_source中,需要通过fields api来获取。

3、创建runtime field的方式

3.1 通过mapping的方式创建

3.1.1、添加runtime field

PUT /index_script_fields
{
"mappings": {
"runtime": {
"aggLineName": {
"type": "keyword",
"script": {
"source": "emit(doc['lineName'].value)"
}
}
},
"properties": {
"lineId": {
"type": "keyword"
},
"lineName": {
"type": "text"
}
}
}
}

3.1.2、更新 runtime field

POST /index_script_fields/_mapping
{
"runtime": {
"aggLineName": {
"type": "keyword",
"script": {
"source": "emit(doc['lineName'].value)"
}
}
}
}

3.1.3、删除runtime field

POST /index_script_fields/_mapping
{
"runtime": {
"aggLineName": null
}
}

3.2 通过search request定义runtime field

GET /index_script_fields/_search
{
"runtime_mappings": {
"lineName": {
"type": "keyword",
"script": "emit(params['_source']['lineName']+'new')"
}
},
"query": {
"match_all": {}
},
"fields": [
"lineName"
]
}

通过search request定义runtime field

4、需求

我们存在一个线路mapping,其中lineName在设计的使用使用了text类型,现在我们需要根据这个字段来进行聚合操作,那么使用runtime field该如何操作呢?

5、实现

5.1 mapping

PUT /index_script_fields
{
"mappings": {
"properties": {
"lineId": {
"type": "keyword"
},
"lineName": {
"type": "text"
}
}
}
}

注意此时的lineName的类型是text

5.2 插入数据

PUT /index_script_fields/_bulk
{"index":{"_id":1}}
{"lineId":"line-01","lineName":"线路A"}
{"index":{"_id":2}}
{"lineId":"line-01","lineName":"线路A"}
{"index":{"_id":3}}
{"lineId":"line-02","lineName":"线路C"}

5.3、根据线路来进行聚合

从上方的mapping中可以lineNametext类型,是不可进行聚合操作的,那么此时我们想进行聚合操作,就可以使用runtime field来实现。

5.3.1 不使用runtime field

不使用runtime field

5.3.2 使用runtime field

5.3.2.1 dsl

GET /index_script_fields/_search
{
"runtime_mappings": {
"aggLineName": {
"type": "keyword",
"script": "emit(params['_source']['lineName']+'new')"
}
},
"query": {
"match_all": {}
},
"fields": [
"lineName"
],
"aggs": {
"agg_line_name": {
"terms": {
"field": "aggLineName",
"size": 10
}
}
}
}

5.3.2.2 java代码

@Test
@DisplayName("lineName字段是text类型,无法进行聚合操作,定义一个runtime field来进行聚合操作")
public void test01() throws IOException {
SearchRequest request = SearchRequest.of(searchRequest ->
searchRequest.index(INDEX_NAME)
// 查询所有数据
.query(query -> query.matchAll(matchAll -> matchAll))
// runtime field字段不会出现在 _source中,需要使用使用 fields api来获取
.fields(fields -> fields.field("lineName"))
// 创建一个 runtime filed 字段类型是 keyword
.runtimeMappings("aggLineName", runtime ->
runtime
// 此处给字段类型为keyword
.type(RuntimeFieldType.Keyword)
.script(script ->
script.inline(inline ->
// runtime field中如果使用 painless脚本语言,需要使用emit
inline.lang(ScriptLanguage.Painless)
.source("emit(params['_source']['lineName']+'new')")
)
)
)
// 进行聚合操作
.aggregations("agg_line_name", agg ->
// 此处的 aggLineName即为上一步runtime field的字段
agg.terms(terms -> terms.field("aggLineName").size(10))
)
.size(100)
);

System.out.println("request: " + request);
SearchResponse<Object> response = client.search(request, Object.class);
System.out.println("response: " + response);

5.3.3.3 运行结果

聚合

6、完整代码

https://gitee.com/huan1993/spring-cloud-parent/blob/master/es/es8-api/src/main/java/com/huan/es8/runtimefield/RuntimeFieldCorrectMappingError.java

7、参考链接

1、https://www.elastic.co/guide/en/elasticsearch/reference/8.6/runtime.html​

责任编辑:武晓燕 来源: 今日头条
相关推荐

2021-06-09 09:36:18

DjangoElasticSearLinux

2021-08-10 07:27:42

ASP.NETFluentd日志

2021-11-02 13:54:41

ElasticSear.NET程序

2009-06-30 16:52:30

DetchedCrit

2023-08-25 09:17:38

2020-09-07 11:30:47

ElasticSear索引Linux

2021-03-18 15:10:42

ElasticSearBeta日志

2013-12-13 17:21:14

Lua脚本语言

2023-11-17 12:04:39

GORM并发

2017-06-07 15:51:50

AndroidAndroid Stuapt

2009-06-25 16:49:24

Hibernate

2023-04-12 15:25:09

Bytrace鸿蒙

2011-07-08 13:28:10

XCode SVN

2013-01-07 13:54:17

Android开发JUnit单元测试

2013-01-14 12:53:13

Firefox OSIndexedDB

2024-02-29 08:02:00

2024-08-01 10:10:24

MySQL场景搜索

2021-05-11 09:02:34

OpenSearch存储Elastcsearc

2024-06-26 19:14:53

2023-12-29 08:33:17

点赞
收藏

51CTO技术栈公众号