当前位置: 首页 > 后端技术 > Java

简单使用elasticsearch中的script_fields

时间:2023-04-01 20:27:51 Java

1.背景我们在使用es的时候,有时候需要动态返回一些字段,而这些字段是动态计算的,那么这时候怎么操作呢?比如:我们的索引中有一个sex字段,存储为1或者0,需要在页面显示男性或者女性,那么就可以使用script_fields来解决这个问题。可能有人会说我可以通过后台格式化,但是假设我们需要在kibana等可视化工具上展示呢?2、准备数据2.1mappingPUT/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":"张三","性别":1,"爱好":["足球","篮球"],"地址":{"省":"湖北","城市":"city01"}}{"index":{"_id":2}}{"name":"张三","sex":2,"address":{"province":"北京","city":"city01"}}{"index":{"_id":3}}{"name":"张三","hobbies":["football"],"address":{"province":"湖北","city":"city01"}}注意:需要注意的是id=3的数据是没有sex属性的,那么如何保证painless脚本不报错3.Case3.1格式gender1-male2-female-1-unknown如果没有sex字段,则显示--其余显示**3.1.1dslGET/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"male";}elseif(doc['sex'].value==2){return"female";}elseif(doc['sex'].value==-1){return"unknown";}else{return"**";}"""}}}}注意sex字段不存在,如何判断,看上面代码3.1.2java代码@Test@DisplayName("Formatgender1-male2-female-1-unknown如果sex不存在则显示--其余显示**")publicvoidtest01()throwsIOException{SearchRequestrequest=SearchRequest.of(searchRequest->searchRequest.index(INDEX_NAME).query(query->query.matchAll(matchAll->matchAll))//如果不加这句,_source不会返回,值返回字段.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"+"}elseif(doc['sex'].value==2){\n"+"return\"女\";\n"+"}elseif(doc['sex'].value==-1){\n"+"return\"未知\";\n"+"}else{\n"+"返回\"**\";\n"+"}")))).size(100));System.out.println("请求:"+request);SearchResponseresponse=client.search(request,Object.class);System.out.println("response:"+response);}3.1.3运行结果3.2判断用户是否有爱好3.2.1dslGET/index_script_fields/_search{"_source":["*"],"query":{"match_all":{}},"script_fields":{"has_hobby":{"script":{"lang":"painless","source":"""//如果没有hobbies字段,返回false直接if(doc['hobbies'].size()==0){returnfalse;}returndoc['hobbies'].indexOf(params.hobby)>-1;""","params":{"hobby":"篮球"}}}}}3.2.2java代码@Test@DisplayName("判断用户是否有某种爱好")publicvoidtest02()throwsIOException{SearchRequestrequest=SearchRequest.of(searchRequest->searchRequest.index(INDEX_NAME).query(query->query.matchAll(matchAll->matchAll))//如果不加这句,那么_source不会返回,值返回字段.lang(ScriptLanguage.Painless).source("//没有hobbies字段,直接返回false\n"+"if(doc['hobbies'].size()==0){\n"+"返回false;\n"+"}\n"+"返回doc['hobbies'].indexOf(params.hobby)>-1;").params("爱好",JsonData.of("篮球"))))).size(100));System.out.println("请求:"+request);SearchResponseresponse=client.search(request,Object.class);System.out.println("response:"+response);}3.2.3运行结果3.3湖北用户数统计3.3.1dslGET/index_script_fields/_search{"query":{"match_all"t;:{}},"aggs":{"agg_province":{"sum":{"script":{"lang":"painless","source":"""//因为地址是复杂类型,所以不能通过doc直接访问if(params['_source']['address']['province']=='Hubei'){return1;}return0;"""}}}}}因为address是复杂类型,所以不能直接通过doc访问,只能通过params[_source]访问3.3.2java代码@Test@DisplayName("湖北省用户数统计")publicvoidtest03()throwsIOException{SearchRequestrequest=SearchRequest.of(searchRequest->searchRequest.index(INDEX_NAME).query(query->query.matchAll(matchAll->matchAll))//如果不加这句,_source不会return,返回值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']['省']=='湖北'){\n"+"return1;\n"+"}\n"+“返回0;”))))).size(100));System.out.println("请求:"+request);SearchResponseresponse=client.search(request,Object.class);系统。out.println("response:"+response);}3.3.3运行结果![运行结果![](https://img-blog.csdnimg.cn/5...)4、doc[..]它和params_source有什么区别通过上面的案例,我们发现我们有时通过doc[..]访问属性,有时通过params['_source'][..]访问属性,那么这两种访问有什么不同呢?doc[..]:使用doc关键字,将导致该字段的条款被加载到内存中(缓存),这将导致执行速度更快,但内存消耗更多。此外,doc[…]表示法仅允许简单的值字段(您不能从中返回json对象),并且仅对非分析或基于单项的字段有意义。但是,如果可能,使用doc仍然是访问记录值的推荐方法。params[_source][..]:每次使用_source都要加载解析,所以使用_source会比较慢。虽然访问_source比访问doc值慢,但是script_fields只是对需要返回的文档执行脚本,所以不会对性能造成太大影响,除非返回的数据特别大。5.完整代码https://gitee.com/huan1993/spring-cloud-parent/blob/master/es/es8-api/src/main/java/com/huan/es8/script/ScriptFieldApi.java6.参考文档1.https://www.elastic.co/guide/en/elasticsearch/reference/8.6/search-fields.html#script-fields