ES[7.9]script脚本操作

ES中的script脚本操作

GET product2/_search
POST product2/_update/4
{
  "script": {
    "source": "ctx._source.price -=10"
  }
}
#简写
POST product2/_update/4
{
  "script": "ctx._source.price -=10;ctx._source.name += '程飞'"
}
GET product2/_doc/4

利用传参的方式,这样的效率更高,因为当你批量修改的时候,script代码只会编译一次

POST product2/_update/4
{
  "script": {
    "lang": "painless",
    "source": "ctx._source.tags.add(params.tag_name)",
    "params": {"tag_name":"无线充电"}
  }
}

delete删除操作

GET product2/_doc/5
POST product2/_update/5
{
  "script": {
    "lang": "painless",
    "source": "ctx.op='delete'"
  }  
}

upsert如果对应的id有数据,就直接update,如果没有,就用upsert的数据进行insert的操作

GET product2/_doc/4
POST product2/_update/4
{
  "script": {
    "lang": "painless", 
    "source": "ctx._source.price += params.par"
    , "params": {
      "par":100
    }
  },
  "upsert": {
    "name":"小米10",
    "price":4999
  }
}

正则表达式如果未启用 会报错,我们需要在配置文件elasticsearch.yml进行如下的配置 script.painless.regex.enabled: true

正则我们一般很少用,他的性能不好,而且会绕过 painless针对长时间运行和占用内存的脚本的保护措施,而且有深度堆栈行为

GET product2/_doc/1
POST  product2/_update/1
{
  "script": {
    "lang": "painless",
    "source": """
      if(ctx_source.name =~ /[\s\S]*phone[\s\S]*/){
        ctx._source.name += "***";
      }else{
        ctx.op  = "noop";
      }
    """
  }
}

[0-9]{4}-[0-9]{2}-[0-9]{2}匹配出来的不一定是日期 比如 9999-99-99 但是日期一定能匹配上

=是模糊匹配,==是完全匹配

POST product2/_update/1
{
  "script": {
    "lang": "painless",
    "source": """
      if (ctx._source.createtime ==~ /[0-9]{4}-[0-9]{2}-[0-9]{2}/) {
        ctx._source.name += "|***";
      } else {
        ctx.op = "noop";
      }
    """
  }
}

改成_bulk批量操作呢,_bulk是不能换行符的,不然会报错

GET product2/_doc/4
POST product2/_bulk
{
  "update":{
    "_id":4,
    "retry_on_conflict":3
  }
}
{
  "script":{
    "source":"ctx._source.price += params.par",
    "lang":"painless",
    "params":{"par":10000}
  },
  "upsert":{
    "name":"红米旗舰版",
    "price":15986
  }
}
POST product2/_bulk
{"update":{"_id":4,"retry_on_conflict":3}}
{"script":{"source":"ctx._source.price += params.par","lang":"painless","params":{"par":10000}},"upsert":{"name":"红米旗舰版","price":15986}}

GET查询 除了painless(默认) ES还支持 (了解)

expression(快速的自定义排名和排序)

mustache(范本)

java(专家API)

这些语言应用场景更窄,但是可能性能更好

GET product2/_search
{
  "script_fields": {
    "test_field": {
      "script": {
        "lang":   "expression",
        "source": "doc['price']"
      }
    }
  }
}

_search的script脚本操作,如果source中的字段没有,就会报错

GET product2/_search
GET product2/_search
{
  "script_fields": {
    "test_bala": {
      "script": {
        "lang": "painless", 
        "source": "doc['price'].value*9"
      }
    }
  }
}

更换num的值 对比took消耗

doc['price'] * num只编译一次而doc['price'] * 9 会随着数字改变而一直编译,ES默认每分钟支持15次编译

GET product2/_search
{
  "script_fields": {
    "test_field": {
      "script": {
        "lang":   "expression",
        "source": "doc['price'] * num",
        "params": {
          "num": 6
        }
      }
    }
  }
}

例如 打8折价格

GET product2/_search
{
  "script_fields": {
    "chengfei": {
      "script": {
        "source": "doc.price.value*params.discount",
        "params": {
          "discount":0.8
        }
      }
    }
  }
}

原始价格 和 多个打折价格

GET product2/_search
{
  "script_fields": {
    "discount": {
      "script": {
        "source": "[doc['price'].value * params.discount_8,doc['price'].value * params.discount_7]"
        , "params": {
          "discount_8":0.8,
          "discount_7":0.7
        }
      }
    }
  }
}
POST /product/_refresh

Stored scripts :可以理解为script模板 缓存在集群的cache中

/_scripts/{id} 类似存储过程 计算折扣 作用域为整个集群

默认缓存大小是100MB 没有过期时间 可以手工设置过期时间script.cache.expire 通过script.cache.max_size设置缓存大小 脚本最大64MB 通过script.max_size_in_bytes配置 只有发生变更时重新编译

这里设置的discount变量是让使用它的程序传入的,相当于是存储过程,或是函数

POST _scripts/bala1
{
  "script":{
    "lang": "painless", 
    "source": "doc['price'].value * params.discount"
  }
}
GET _scripts/bala

GET product2/_search
{
  "script_fields": {
    "bala": {
      "script": {
        "id": "bala",
        "params": {
          "discount":0.5
        }
      }
    }
  }
}

Dates

官网Bug: 日期字段公开为 ZonedDateTime,因此它们支持诸如之类的方法getYear,getDayOfWeek 或例如从历元开始到毫秒getMillis。要在脚本中使用它们,请省略get前缀并继续使用小写的方法名其余部分。例如,以下代码返回每个冰球运动员的出生年份getYear()

getMonth()

getDayOfMonth()

getDayOfWeek()

getDayOfYear()

getHour()

getMinute()

getSecond()

getNano()

当然了前提是你的字段是时间类型是date的而且写法一定要是

GET product2/_search
PUT my_index2
{
  "mappings": {
    "properties": {
      "name":{"type": "keyword"},
      "create_time":{"type": "date"}
    }
  }
}
POST /my_index3/_bulk
{"index":{"_id":1}}
{"name":"chengfei","create_time":"2015-01-01T12:10:30Z"}
{"index":{"_id":2}}
{"name":"xuxu","create_time":"2015-01-01T18:10:30Z"}
GET /my_index3/_mapping
GET my_index/_search
GET /my_index3/_search
{
  "script_fields": {
    "date_test": {
      "script": {
        "source": "doc.create_time.value.hour"
      }
    }
  }
}

下面的这种日期方法也行,只要是index插入的默认数据类型是date的都行,根据官网,这种日期写法确实也是date类型的,官网对于date类型的描述

POST /my_index4/_bulk
{"index":{"_id":1}}
{"name":"chengfei","create_time":"2015/01/01 23:50:30"}
{"index":{"_id":2}}
{"name":"xuxu","create_time":"2015/01/01 12:10:30"}
GET /my_index4/_mapping
GET my_index/_search
GET /my_index4/_search
{
  "script_fields": {
    "date_test": {
      "script": {
        "source": "[doc.create_time.value.minute,doc.create_time.value.dayOfWeek]"
      }
    }
  }
}

那么遇到复杂脚本,写很多行怎么办呢

GET product2/_search
POST product2/_update/3
{
  "script": {
    "lang": "painless",
    "source": """
      ctx._source.name += params.name;
      ctx._source.price -= params.price
    """,
    "params": {
      "name":"无线充电宝",
      "price":100
    }
  }
}

聚合查询的使用

统计所有价格小于1000商品tag的 数量 不考虑去重

GET product2/_search
{
  "query": {
    "bool": {
      "filter": [
        {"range": {
          "price": {
            "lt": 1000
          }
        }}
      ]
    }
  },
  "aggs": {
    "script_aggs_test": {
      "terms": {
        "field": "tags.keyword",
        "size": 10
      }
    }
  }
}

GET product/_search
{
  "query": {
    "bool": {
      "filter": [
        {"range": {
          "price": {
            "lt": 1000
          }
        }}
      ]
    }
  },
  "aggs": {
    "script_aggs_test": {
      "sum": {
        "script": {
          "lang": "painless",
          "source": """
            int total = 0;
            for (int i = 0 ;i<doc.tags.length;i++){
              total ++
            }
            return total;
          """
        }
      }
    }
  }
}

以下为案件的嫌疑人信息

统计男性嫌疑人的数量

如果字段是复杂类型,如数组或是object的话,就不能直接用doc的方式,要用params._source的方式获取

GET test_index/_search
DELETE test_index
PUT test_index/_bulk?refres
{"index":{"_id":1}}
{"ajbh": "12345","ajmc": "立案案件","lasj": "2020/05/21 13:25:23","jsbax_sjjh2_xz_ryjbxx_cleaning": [{"XM": "张三","NL": "30","SF": "男"},{"XM": "李四","NL": "31","SF": "男"},{"XM": "王五","NL": "30","SF": "女"},{"XM": "赵六","NL": "23","SF": "男"}]}
{"index":{"_id":2}}
{"ajbh": "563245","ajmc": "结案案件","lasj": "2020/05/21 13:25:23","jsbax_sjjh2_xz_ryjbxx_cleaning": [{"XM": "张三2","NL": "30","SF": "男"},{"XM": "李四2","NL": "31","SF": "男"},{"XM": "王五2","NL": "30","SF": "女"},{"XM": "赵六2","NL": "23","SF": "女"}]}
{"index":{"_id":3}}
{"ajbh": "12345","ajmc": "立案案件","lasj": "2020/05/21 13:25:23","jsbax_sjjh2_xz_ryjbxx_cleaning": [{"XM": "张三3","NL": "30","SF": "男"},{"XM": "李四3","NL": "31","SF": "男"},{"XM": "王五3","NL": "30","SF": "女"},{"XM": "赵六3","NL": "23","SF": "男"}]}

GET test_index/_search
{
  "aggs": {
    "how_much_man": {
      "sum": {
        "script": {
          "lang": "painless",
          "source": """
            int total = 0;
            for(int i = 0;i<params._source.jsbax_sjjh2_xz_ryjbxx_cleaning.length;i++){
              
              if(params._source.jsbax_sjjh2_xz_ryjbxx_cleaning[i].SF=="男"){
                total++;
              }
            }
            return total;
          """
        }
      }
    }
  }
}

GET test_index/_search
{
  "aggs": {
    "how_much_man": {
      "sum": {
        "script": {
          "lang": "painless",
          "source": """
            int total = 0;
            for(int i = 0;i<params['_source']['jsbax_sjjh2_xz_ryjbxx_cleaning'].length;i++){
              if(params['_source']['jsbax_sjjh2_xz_ryjbxx_cleaning'][i]['SF']=='男'){
                total++;
              }
            }
            return total;
          """
        }
      }
    }
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容