首页 > 其他分享 >在elasticsearch中简单的使用script_fields

在elasticsearch中简单的使用script_fields

时间:2023-01-31 13:23:46浏览次数:72  
标签:return script fields sex source elasticsearch doc

目录

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"
          }
        }
      }
    }
  }
}

注意:

  1. hobbies其实是一个数组类型
  2. 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"}}

注意:

  1. 需要注意一下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 运行结果

![运行结果![](/i/ll/?i=5910495ac0814db393125dae96934e38.png)

4、doc[..]和params[_source][..]有何不同

通过上面的案例,我们发现,我们有些时候是通过doc[..]来访问属性的,有些时候是通过params['_source'][..]来访问,那么这2种访问方式有何不同呢?

doc[..]:使用doc关键字,将导致该字段的术语被加载到内存(缓存),这将导致更快的执行,但更多的内存消耗。此外,doc[…]表示法只允许简单的值字段(您不能从中返回json对象),并且仅对非分析或基于单个术语的字段有意义。然而,如果可能的话,使用doc仍然是访问文档值的推荐方法。
params[_source][..]: 每次使用_source都必须加载和解析, 因此使用_source会相对而言要慢点。

虽然访问_source比访问doc values要慢,但是script_fields只对需要返回文档执行脚本,因此也不会太影响性能,除非返回的数据特别多。

在这里插入图片描述

5、完整代码

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

6、参考文档

1、https://www.elastic.co/guide/en/elasticsearch/reference/8.6/search-fields.html#script-fields

标签:return,script,fields,sex,source,elasticsearch,doc
From: https://www.cnblogs.com/huan1993/p/17078649.html

相关文章

  • JavaScript学习笔记—DOM:属性节点
    属性也是一个节点对象(Attr),和文本一样,通常我们不会去直接获取节点对象,而是通过元素来完成对属性的操作:方式一:读取:元素.属性名(注意,class属性需要使用className来读取)读......
  • 关于IDEA运行时报内存溢出FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - Jav
    IDEA运行时,经常会碰到内存溢出问题:FATALERROR:CALL_AND_RETRY_LASTAllocationfailed-JavaScriptheapoutofmemory,非常讨厌,浪费时间,现记录解决方案如下:1、全......
  • javascript:js 读写 style属性(DOM模型)
    javascript:js读写style属性(DOM模型)    一、说明: 1、js读取style属性,需要去掉css格式中的“-”,“-”后面的第一个字母大写。js中的减号(“-”),与css中属性......
  • 痛恨 JavaScript 每一天(缺少指针)
    背景二叉搜索树,插入节点JavaScript解法functioninsertNode(root,newNode){if(newNode.key<root.key){if(root.left){insertNode(r......
  • JavaScript JSON
    什么是JSONJSON的作用:JSON是用于存储和传输数据的格式;JSON通常用于服务端向网页传输数据;什么是JSON:JSON全称为:JavaScriptObjectNotation是一种轻量级的数据交......
  • JavaScript之this、let、const关键字
    各场景下的thisthis的意思:百度翻译为:这、这么、本在JavaScript中,表示当前对象的引用关键字,没有特殊含义。在一个方法中,this表示该方法所属的对象。如果单独使用,this表......
  • typescript入门
    js数据类型:7种原始类型:BooleanNullUndefinedNumberBigintStringSymbolObject类型letisDone:boolean=falseletnum:number=10letstr:string=`num=......
  • javaScript一个数组对象根据另一个数组排序
    varlist=[{name:'上海',code:'shanghai',},{name:'西安',code:'xian'},{name:'深圳',code:'shenzhen'},{name:'北京',code:'beijing'}];list......
  • JavaScript学习笔记—DOM之文本节点
    在DOM中,文本内容也是一个节点对象(Text),可以通过获取文本对象然后完成对它的各种操作,但这种做法会使得事情变得复杂,并不建议这么做。在大部分场景下,可以通过元素的属性来操作......
  • [Typescript 5.0] const Type Parameters with readonly
    https://devblogs.microsoft.com/typescript/announcing-typescript-5-0-beta/#exhaustive-switch-case-completions Intheexamplecode:typeHasNames={names:r......