在elasticsearch中简单的使用script_fields
1、背景
在我们使用es时,有些时候需要动态返回一些字段,而这些字段是通过动态计算得出的,那么此时该如何操作呢? 比如:我们索引中有一个sex字段,保存的是1或0,而在页面上需要展示男或女,那么这个时候就可以使用script_fields来解决。可能有些人说,我通过后台进行格式化一下不就行了吗,但是假设我们需要在kibana等可视化工具上展示呢?
2、准备数据
2.1 mapping
PUT /index_script_fields
{
"mappings": {
"properties": {
"name":{
"type": "keyword"
},
"sex":{
"type": "integer"
},
"hobbies":{
"type":"keyword"
},
"address":{
"properties": {
"province":{
"type":"keyword"
},
"city":{
"type":"keyword"
}
}
}
}
}
}
注意:
hobbies其实是一个数组类型address是一个Object类型,即是一个复杂类型
2.2 插入数据
PUT /index_script_fields/_bulk
{"index":{"_id":1}}
{"name":"张三","sex":1,"hobbies":["足球","篮球"],"address":{"province":"湖北","city":"city01"}}
{"index":{"_id":2}}
{"name":"张三","sex":2,"address":{"province":"北京","city":"city01"}}
{"index":{"_id":3}}
{"name":"张三","hobbies":["足球"],"address":{"province":"湖北","city":"city01"}}
注意:
- 需要注意一下
id=3的数据是没有sex属性的,那么在painless脚本中如何保证不报错。
3、案例
3.1 格式化性别 1-男 2-女 -1-未知 如果不存在sex字段,则显示-- 其余的显示 **
3.1.1 dsl
GET /index_script_fields/_search
{
"query": {
"match_all": {}
},
"_source": ["*"],
"script_fields": {
"sex_format": {
"script": {
"lang": "painless",
"source": """
// 判断 sex 字段是否存在
if(doc['sex'].size() == 0){
return "--";
}
if(doc['sex'].value == 1){
return "男";
}else if(doc['sex'].value == 2){
return "女";
}else if(doc['sex'].value == -1){
return "未知";
}else{
return "**";
}
"""
}
}
}
}
需要注意 sex 字段不存在,该如何判断,见上方的代码
3.1.2 java代码
@Test
@DisplayName("格式化性别 1-男 2-女 -1-未知 如果不存在sex字段,则显示-- 其余的显示 **")
public void test01() throws IOException {
SearchRequest request = SearchRequest.of(searchRequest ->
searchRequest.index(INDEX_NAME)
.query(query -> query.matchAll(matchAll -> matchAll))
// 不加这句,则 _source 不会返回,值返回 fields
.source(config -> config.filter(filter -> filter.includes("*")))
.scriptFields("sex_format", field ->
field.script(script ->
script.inline(inline ->
inline.lang(ScriptLanguage.Painless)
.source(" // 判断 sex 字段是否存在\n" +
" if(doc['sex'].size() == 0){\n" +
" return \"--\";\n" +
" }\n" +
" \n" +
" if(doc['sex'].value == 1){\n" +
" return \"男\";\n" +
" }else if(doc['sex'].value == 2){\n" +
" return \"女\";\n" +
" }else if(doc['sex'].value == -1){\n" +
" return \"未知\";\n" +
" }else{\n" +
" return \"**\";\n" +
" }")
)
)
)
.size(100)
);
System.out.println("request: " + request);
SearchResponse<Object> response = client.search(request, Object.class);
System.out.println("response: " + response);
}
3.1.3 运行结果

3.2 判断用户是否有某个爱好
3.2.1 dsl
GET /index_script_fields/_search
{
"_source": ["*"],
"query": {"match_all": {}},
"script_fields": {
"has_hobby": {
"script": {
"lang": "painless",
"source": """
// 没有hobbies字段,直接返回 false
if(doc['hobbies'].size() == 0){
return false;
}
return doc['hobbies'].indexOf(params.hobby) > -1;
""",
"params": {
"hobby":"篮球"
}
}
}
}
}
3.2.2 java代码
@Test
@DisplayName("判断用户是否有某个爱好")
public void test02() throws IOException {
SearchRequest request = SearchRequest.of(searchRequest ->
searchRequest.index(INDEX_NAME)
.query(query -> query.matchAll(matchAll -> matchAll))
// 不加这句,则 _source 不会返回,值返回 fields
.source(config -> config.filter(filter -> filter.includes("*")))
.scriptFields("has_hobby", field ->
field.script(script ->
script.inline(inline ->
inline.lang(ScriptLanguage.Painless)
.source(" // 没有hobbies字段,直接返回 false\n" +
" if(doc['hobbies'].size() == 0){\n" +
" return false;\n" +
" }\n" +
" return doc['hobbies'].indexOf(params.hobby) > -1;")
.params("hobby", JsonData.of("篮球"))
)
)
)
.size(100)
);
System.out.println("request: " + request);
SearchResponse<Object> response = client.search(request, Object.class);
System.out.println("response: " + response);
}
3.2.3 运行结果

3.3 统计湖北的用户有几个
3.3.1 dsl
GET /index_script_fields/_search
{
"query": {"match_all": {}},
"aggs": {
"agg_province": {
"sum": {
"script": {
"lang": "painless",
"source": """
// 因为 address 是一个复杂类型,因此不可直接通过 doc 来访问
if(params['_source']['address']['province'] == '湖北'){
return 1;
}
return 0;
"""
}
}
}
}
}
因为 address 是一个复杂类型,因此不可直接通过 doc 来访问,只能通过 params[_source]来访问
3.3.2 java代码
@Test
@DisplayName("统计湖北省下的用户有几个")
public void test03() throws IOException {
SearchRequest request = SearchRequest.of(searchRequest ->
searchRequest.index(INDEX_NAME)
.query(query -> query.matchAll(matchAll -> matchAll))
// 不加这句,则 _source 不会返回,值返回 fields
.source(config -> config.filter(filter -> filter.includes("*")))
.aggregations("agg_province", agg->
agg.sum(sum ->
sum.script(script ->
script.inline(inline ->
inline.lang(ScriptLanguage.Painless)
// 因为 address 是一个复杂类型,因此不可直接通过 doc 来访问, 只可通过 params['_source']来访问
.source("// 因为 address 是一个复杂类型,因此不可直接通过 doc 来访问\n" +
" if(params['_source']['address']['province'] == '湖北'){\n" +
" return 1;\n" +
" }\n" +
" return 0;")
)
)
)
)
.size(100)
);
System.out.println("request: " + request);
SearchResponse<Object> response = client.search(request, Object.class);
System.out.println("response: " + response);
}
3.3.3 运行结果

4、doc[..]和params[_source][..]有何不同
通过上面的案例,我们发现,我们有些时候是通过doc[..]来访问属性的,有些时候是通过params['_source'][..]来访问,那么这2种访问方式有何不同呢?
doc[..]:使用doc关键字,将导致该字段的术语被加载到内存(缓存),这将导致更快的执行,但更多的内存消耗。此外,doc[…]表示法只允许简单的值字段(您不能从中返回json对象),并且仅对非分析或基于单个术语的字段有意义。然而,如果可能的话,使用doc仍然是访问文档值的推荐方法。
params[_source][..]: 每次使用_source都必须加载和解析, 因此使用_source会相对而言要慢点。
虽然访问_source比访问doc values要慢,但是script_fields只对需要返回文档执行脚本,因此也不会太影响性能,除非返回的数据特别多。

5、完整代码
6、参考文档
1、https://www.elastic.co/guide/en/elasticsearch/reference/8.6/search-fields.html#script-fields
在elasticsearch中简单的使用script_fields的更多相关文章
- ElasticSearch中的简单查询
前言 最近修改项目,又看了下ElasticSearch中的搜索,所以简单整理一下其中的查询语句等.都是比较基础的.PS,好久没写博客了..大概就是因为懒吧.闲言少叙书归正传. 查询示例 http:// ...
- 如何在Elasticsearch中安装中文分词器(IK+pinyin)
如果直接使用Elasticsearch的朋友在处理中文内容的搜索时,肯定会遇到很尴尬的问题--中文词语被分成了一个一个的汉字,当用Kibana作图的时候,按照term来分组,结果一个汉字被分成了一组. ...
- elasticsearch中常用的API
elasticsearch中常用的API分类如下: 文档API: 提供对文档的增删改查操作 搜索API: 提供对文档进行某个字段的查询 索引API: 提供对索引进行操作,查看索引信息等 查看API: ...
- 在Elasticsearch中查询Term Vectors词条向量信息
这篇文章有点深度,可能需要一些Lucene或者全文检索的背景.由于我也很久没有看过Lucene了,有些地方理解的不对还请多多指正. 更多内容还请参考整理的ELK教程 关于Term Vectors 额, ...
- elasticsearch中的API
elasticsearch中的API es中的API按照大类分为下面几种: 文档API: 提供对文档的增删改查操作 搜索API: 提供对文档进行某个字段的查询 索引API: 提供对索引进行操作 查看A ...
- 使用Hive或Impala执行SQL语句,对存储在Elasticsearch中的数据操作(二)
CSSDesk body { background-color: #2574b0; } /*! zybuluo */ article,aside,details,figcaption,figure,f ...
- 使用Hive或Impala执行SQL语句,对存储在Elasticsearch中的数据操作
http://www.cnblogs.com/wgp13x/p/4934521.html 内容一样,样式好的版本. 使用Hive或Impala执行SQL语句,对存储在Elasticsearch中的数据 ...
- laravel Scout包在elasticsearch中的应用
laravel Scout包在elasticsearch中的应用 laravel的Scout包是针对自身的Eloquent模型开发的基于驱动的全文检索引擎.意思就是我们可以像使用ORM一样使用检索功能 ...
- Elasticsearch中的相似度模型(原文:Similarity in Elasticsearch)
原文链接:https://www.elastic.co/blog/found-similarity-in-elasticsearch 原文 By Konrad Beiske 翻译 By 高家宝 译者按 ...
- 探究ElasticSearch中的线程池实现
探究ElasticSearch中的线程池实现 ElasticSearch里面各种操作都是基于线程池+回调实现的,所以这篇文章记录一下java.util.concurrent涉及线程池实现和Elasti ...
随机推荐
- Istio(九):istio安全之授权
目录 一.模块概览 二.系统环境 三.istio授权 3.1 istio授权 3.2 来源 3.3 操作 3.4 条件 四.实战:授权(访问控制) 4.1 访问控制 4.2 清理 一.模块概览 在Ku ...
- 我用EasyExcel优化了公司的导出(附踩坑记录)
背景介绍 最近要改一个导出的功能,在原有的基础上,在导出一份明细数据,要求导出内容加在原有 excel 的第二个 sheet 上.考虑到数据量还比较大,干脆引入阿里的 EasyExcel 来做. 下面 ...
- 「浙江理工大学ACM入队200题系列」问题 J: 零基础学C/C++83——宁宁的奥数路
本题是浙江理工大学ACM入队200题第八套中的J题 我们先来看一下这题的题面. 题面 题目描述 宁宁参加奥数班,他遇到的第一个问题是这样的:口口口+口口口=口口口,宁宁需要将1~9 九个数分别填进对应 ...
- Jenkinsfile 同时检出多个 Git 仓库
前置 通常,在 Jenkinsfile 中使用 Git 仓库是这样的: stage('Checkout git repo') { steps { checkout([ $class: 'GitSCM' ...
- Git+Github协作开发流程
采用合作开发者的方式进行协作开发,下面以zlcook和zlserver合作开发iqas-ios-record项目为例进行讲解,zlcook为项目创建者,zlserver为项目参与者.协作开发步骤如下: ...
- 刚哥谈架构(八)- 为你的应用选择合适的API
前言: 架构师的主要活动是做出正确的技术决策.选择合适的API是一项重要的技术决策.那么今天就看看API的选择问题. 应用程序编程接口(API)是一种计算接口,它定义了多个软件中介之间的交互.它定义了 ...
- 【云原生 · DevOps】DevOps 解决方案
DevOps 解决方案 1.1 容器化 CI/CD 1.2 容器化流水线 1.3 深度集成 Jenkins 1.4 灰度发布 1.5 制品库设计 1.6 DevOps 安全 1.6.1 CI/CD 安 ...
- Java开发学习(四十二)----MyBatisPlus查询语句之条件查询
一.条件查询的类 MyBatisPlus将书写复杂的SQL查询条件进行了封装,使用编程的形式完成查询条件的组合. 这个我们在前面都有见过,比如查询所有和分页查询的时候,都有看到过一个Wrapper类, ...
- VBA驱动SAP GUI自动化:查找页面元素FindAllByName
我们在VBA中嵌入SAP原生的[脚本录制与回放]功能生成的VBS脚本,可以实现很多自动化操作.但只有我们对SAP做了一系列动作,才会得到这些动作的脚本.然而,一旦我们需要用代码提前做一些判断,然后再决 ...
- Java中遇到的常见问题
一.常用的快捷键 查询对应类:Ctrl+N eclipse的快速生成代码:Alt+Shift+s或sources 加单行注释:Ctrl+/ 运行程序:Ctrl+Shift+F10 搜索:Ctrl+ ...