在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 ...
随机推荐
- CentOS7虚拟机配置git仓库(配置虚拟机,网络,git仓库,windows端git访问)
想要达成的目的:从windows使用git访问CentOS7服务器上搭建的git仓库 用到的软件: (1)VMware-workstation-full-15.5.0-14665864.exe (2) ...
- 如何使用ffmpeg缩小视频的大小?
如何使用ffmpeg缩小视频的大小? 看到这个答案.为方便起见,在下面引用: 通过将1 GB除以以秒为单位的视频长度来计算所需的比特率.因此,对于长度为16:40(1000秒)的视频,请使用10000 ...
- Python基础之模块:2、包的使用和软件开发目录规范及常用内置模块
目录 一.包的使用 1.什么是包 2.包的具体使用 1.常规导入 2.直接导入包名 二.编程思想转变 1.面条阶段 2.函数阶段 3.模块阶段 三.软件目录开发规范 1.bin 2.conf 3.co ...
- 题解合集 (update on 11.5)
收录已发布的题解 按发布时间排序. 部分可能与我的其他文章有重复捏 qwq . AtCoder for Chinese: Link ZHOJ: Link 洛谷 \(1\sim 5\) : [题解]CF ...
- 基于python的数学建模---洛伦兹线与数值解
import numpy as np from scipy.integrate import odeint from mpl_toolkits.mplot3d import Axes3D import ...
- (工具) TCMalloc笔记
下载及编译 wget https://github.com/gperftools/gperftools/releases/download/gperftools-2.9.1/gperftools-2. ...
- OpenCV之C++经典案例
四个案例实战 1.刀片缺陷检测 2.自定义对象检测 3.实时二维码检测 4.图像分割与色彩提取 1.刀片缺陷检测 问题分析 解决思路 尝试二值图像分析 模板匹配技术 代码实现 #include < ...
- Springboot2.6集成Email
Springboot集成Email 老版本 这时候的JavaMailSender是受到Spring的托管的,我们只需要配置参数就行了 !如何判断是否是被Springboot托管的:以下代码IDEA会自 ...
- 进军东南亚市场,腾讯云数据库 TDSQL 助力印尼 BNC 银行数字化转型
腾讯云数据库在助力金融核心系统分布式替换上,已经辐射到了东南亚市场. 东南亚最大的银行之一印尼BNC银行(Bank Neo Commerce)已正式完成新核心分布式迁移,使用腾讯云数据库TDSQL后, ...
- docker给已存在的容器添加或修改端口映射
简述: 这几天研究了一下docker, 发现建立完一个容器后不能增加端口映射了,因为 docker run -p 有 -p 参数,但是 docker start 没有 -p 参数,让我很苦恼,无奈谷歌 ...