经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Elasticsearch » 查看文章
elasticsearch中使用runtime fields
来源:cnblogs  作者:huan1993  时间:2023/2/1 22:37:27  对本文有异议

1、背景

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

2、runtime field介绍

2.1 runtime field可以实现的功能

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

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

  1. PUT /index_script_fields
  2. {
  3. "mappings": {
  4. "runtime": {
  5. "aggLineName": {
  6. "type": "keyword",
  7. "script": {
  8. "source": "emit(doc['lineName'].value)"
  9. }
  10. }
  11. },
  12. "properties": {
  13. "lineId": {
  14. "type": "keyword"
  15. },
  16. "lineName": {
  17. "type": "text"
  18. }
  19. }
  20. }
  21. }

3.1.2、更新 runtime field

  1. POST /index_script_fields/_mapping
  2. {
  3. "runtime": {
  4. "aggLineName": {
  5. "type": "keyword",
  6. "script": {
  7. "source": "emit(doc['lineName'].value)"
  8. }
  9. }
  10. }
  11. }

3.1.3、删除runtime field

  1. POST /index_script_fields/_mapping
  2. {
  3. "runtime": {
  4. "aggLineName": null
  5. }
  6. }

3.2 通过search request定义runtime field

  1. GET /index_script_fields/_search
  2. {
  3. "runtime_mappings": {
  4. "lineName": {
  5. "type": "keyword",
  6. "script": "emit(params['_source']['lineName']+'new')"
  7. }
  8. },
  9. "query": {
  10. "match_all": {}
  11. },
  12. "fields": [
  13. "lineName"
  14. ]
  15. }

通过search request定义runtime field

4、需求

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

5、实现

5.1 mapping

  1. PUT /index_script_fields
  2. {
  3. "mappings": {
  4. "properties": {
  5. "lineId": {
  6. "type": "keyword"
  7. },
  8. "lineName": {
  9. "type": "text"
  10. }
  11. }
  12. }
  13. }

注意此时的lineName的类型是text

5.2 插入数据

  1. PUT /index_script_fields/_bulk
  2. {"index":{"_id":1}}
  3. {"lineId":"line-01","lineName":"线路A"}
  4. {"index":{"_id":2}}
  5. {"lineId":"line-01","lineName":"线路A"}
  6. {"index":{"_id":3}}
  7. {"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

  1. GET /index_script_fields/_search
  2. {
  3. "runtime_mappings": {
  4. "aggLineName": {
  5. "type": "keyword",
  6. "script": "emit(params['_source']['lineName']+'new')"
  7. }
  8. },
  9. "query": {
  10. "match_all": {}
  11. },
  12. "fields": [
  13. "lineName"
  14. ],
  15. "aggs": {
  16. "agg_line_name": {
  17. "terms": {
  18. "field": "aggLineName",
  19. "size": 10
  20. }
  21. }
  22. }
  23. }

5.3.2.2 java代码

  1. @Test
  2. @DisplayName("lineName字段是text类型,无法进行聚合操作,定义一个runtime field来进行聚合操作")
  3. public void test01() throws IOException {
  4. SearchRequest request = SearchRequest.of(searchRequest ->
  5. searchRequest.index(INDEX_NAME)
  6. // 查询所有数据
  7. .query(query -> query.matchAll(matchAll -> matchAll))
  8. // runtime field字段不会出现在 _source中,需要使用使用 fields api来获取
  9. .fields(fields -> fields.field("lineName"))
  10. // 创建一个 runtime filed 字段类型是 keyword
  11. .runtimeMappings("aggLineName", runtime ->
  12. runtime
  13. // 此处给字段类型为keyword
  14. .type(RuntimeFieldType.Keyword)
  15. .script(script ->
  16. script.inline(inline ->
  17. // runtime field中如果使用 painless脚本语言,需要使用emit
  18. inline.lang(ScriptLanguage.Painless)
  19. .source("emit(params['_source']['lineName']+'new')")
  20. )
  21. )
  22. )
  23. // 进行聚合操作
  24. .aggregations("agg_line_name", agg ->
  25. // 此处的 aggLineName即为上一步runtime field的字段
  26. agg.terms(terms -> terms.field("aggLineName").size(10))
  27. )
  28. .size(100)
  29. );
  30. System.out.println("request: " + request);
  31. SearchResponse<Object> response = client.search(request, Object.class);
  32. 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

原文链接:https://www.cnblogs.com/huan1993/p/17084355.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号