elasticsearch_script_01

1. script 简述

elasticsearch的script使用比较灵活而且广泛,有必要先了解和学习一下

1. script的类型和作用

script 可以让你自定义的返回一些field,也可以让你自定义score的计算。
在es中可以使用的script的类型有三种,就像是三种编程语言一样

  1. painless: 这个是最推荐的一种方式
  2. expression: lucene expression
  3. mustache: 这个一般用来定义search_template使用
  4. java

painless 是效率比较好,也比较灵活的一种。后面介绍script的功能的时候也主要以这个为主进行介绍。

2. script使用的方式


"script": {
    "lang":   "...",  
    "source" | "id": "...", 
    "params": { ... } 
  }

source 部分是script的代码或者是 使用id,调用存储的script的id。

2. script的使用场景

在不同的使用场景下script能够使用的doc的field是不相同的。

1. update scripts

在update, update-by-query, reindex API可以通过ctx前缀获取到

  1. ctx._source : doc的_source 字段
  2. ctx.op : 当前操作,index/delete/noop
  3. ctx._index 等: doc的meta-fields,有些是只读的

2. search 和agg 中使用script

script fields 会在每个搜索命中的doc执行一次,其他在search和agg中使用的脚本将针对可能与search或agg匹配的每个文档执行一次,所有的普通字段值可以通过下面方式获取

  1. doc-values : 获取方式为doc[‘cost_price’].value,只有有doc_value的字段才可以这样使用,text字段理论上不能这样用
  2. the _source field : params._source.first_name 这里的params前缀必须要有
  3. stored fields : params._fields[‘first_name’].value

同时还可以在一些特定的查询中获取比如score等字段

3. search中获取doc的打分数据

获取和修改文档的_score字段只能够在 function_score query, script-based sorting, 或者 aggregations 当中
具体的使用方式有不太相同,在function_score中使用 script_score属性,在script-based sorting 中使用_script 属性

script语法,点号“.”表示获取字段,中括号表示获取数组“[]”,对应的样例就是
params._source.first_name
params._fields[‘first_name’].value

3. script灵活使用的一些理解

script可以简单的理解像java一样
常见的数据类型有

  1. 字符串:对应的方法有.length() 方法
  2. 数组[]: 对应的属性有.length 对应的方法有.add() .size() 可以试试看看对应于field的value是不是可以添加元素,可能是根据现有field value的类型来决定的
  3. 正则:/aa/.split(str) 这个也太复杂了,就是java正则的使用,感觉一般情况先应该用不上吧。
  4. 数字

script的逻辑表达式只有两种

  1. if else
  2. for 循环

语法

int x;           
List y;          add(ele) get(1)  y[1]=5  y.length()
int x, y = 5, z; 
def d;           
int i = 10;      
float[] f;      f[0]  f.length  数组类型
Map[][] m;      get(key) m['a']='b'  m.a='a_value'
String r = "some text" 

这个语法有点类似python的语法,比较简练

4. script的使用方式

  1. 直接在某些query中使用script关键字
  2. search中使用script来产生额外的field使用的script_field关键字,然后再嵌套使用script关键字
  3. search的function_score中使用script来自定义score时候使用的script_score关键字,然后再嵌套使用script关键字
  4. search中使用script来产生sort字段的时候在sort字段中嵌套使用_script关键字,然后再嵌套使用 script关键字

5. 样例

1. 在search中使用 script_score功能

在 function_score 查询, script-based 排序(sorting), 或者 aggregations 有能力获取到 _score 字段
需要使用script_score 查询。
比如下面 是在function_score 中改变_score,其他类型的将来遇到再看


PUT my_index/_doc/1?refresh
{
  "text": "quick brown fox",
  "popularity": 1
}


PUT my_index/_doc/2?refresh
{
  "text": "quick fox",
  "popularity": 5
}

PUT my_index/_doc/3?refresh
{
  "text": "quick fox",
  "popularity": 50
}

GET my_index/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "text": "quick brown fox"
        }
      },
      "script_score": {
        "script": {
          "lang": "expression",
          "source": "_score * doc['popularity']"
        }
      }
    }
  }
}

返回


{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 4.0225573,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 4.0225573,
        "_source" : {
          "text" : "quick fox",
          "popularity" : 50
        }
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.2483562,
        "_source" : {
          "text" : "quick brown fox",
          "popularity" : 1
        }
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.4022557,
        "_source" : {
          "text" : "quick fox",
          "popularity" : 5
        }
      }
    ]
  }
}


script base sorting

GET /_search
{
    "query" : {
        "term" : { "user" : "kimchy" }
    },
    "sort" : {
        "_script" : {
            "type" : "number",
            "script" : {
                "lang": "painless",
                "source": "doc['field_name'].value * params.factor",
                "params" : {
                    "factor" : 1.1
                }
            },
            "order" : "asc"
        }
    }
}

agg操作等后面再总结。

2. 获取field的value,通过doc values

使用 doc[‘field_name’]
但是因为string.text field 没有doc-values 所以如果想用这种方式获取的话需要打开 fielddata 设置,这是一个很昂贵的操作。所以尽量不要使用script获取text field的内容。


PUT my_index/_doc/1?refresh
{
  "cost_price": 100
}

GET my_index/_search
{
  "script_fields": {
    "sales_price": {
      "script": {
        "lang":   "expression",
        "source": "doc['cost_price'] * markup",
        "params": {
          "markup": 0.2
        }
      }
    }
  }
}

3. 获取field value 通过_source字段

通过_source.field_name 可以获取到source中对应的字段,但是相对来说比doc-values的要慢很多。

PUT my_index
{
  "mappings": {
    "properties": {
      "first_name": {
        "type": "text"
      },
      "last_name": {
        "type": "text"
      }
    }
  }
}

PUT my_index/_doc/1?refresh
{
  "first_name": "Barry",
  "last_name": "White"
}

GET my_index/_search
{
  "script_fields": {
    "full_name": {
      "script": {
        "lang": "painless",
        "source": "params._source.first_name + ' ' + params._source.last_name"
      }
    }
  }

返回主体
"hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "fields" : {
          "full_name" : [
            "Barry White"
          ]
        }
      }
    ]

上面的script.source中还必须要带params。

4. 获取field value 通过store field

store field是指那些在mapping中定义的mapping param 为 store:true的field
可以使用 _fields[‘field_name’].value or _fields[‘field_name’] 语法

PUT my_index
{
  "mappings": {
    "properties": {
      "full_name": {
        "type": "text",
        "store": true
      },
      "title": {
        "type": "text",
        "store": true
      }
    }
  }
}

PUT my_index/_doc/1?refresh
{
  "full_name": "Alice Ball",
  "title": "Professor"
}

GET my_index/_search
{
  "script_fields": {
    "name_with_title": {
      "script": {
        "lang": "painless",
        "source": "params._fields['title'].value + ' ' + params._fields['full_name'].value"
      }
    }
  }
}


source field也是 store field的一种,所以_source field的性能和store field的性能接近,使用store filed的唯一场景是 _source特别大,我们并不需要获取全部的_source的时候 使用store field会更好。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值