文章目录
-
- [预处理节点ingest node](#预处理节点ingest node)
- [Pipeline & Processor](#Pipeline & Processor)
- [painless script](#painless script)
预处理节点ingest node
ES5.0版本出现的,默认配置下所有节点都是ingest node。可以对index或bulk api 请求进行拦截,对其中数据进行预处理转换,并重新返回index或bulk api。
预处理操作比如:
- 为某个字段设置默认值
- 重命名某个字段
- 对字段值进行split 按某个字符进行拆分操作
- 支持painless script脚本,对数据进行更加复杂的加工
Logstash也能对数据进行预处理操作,ingest node和Logstash最大的区别就是,ingest node是ES中的概念,只能从es的rest api请求中获取数据,并写入ES;而Logstash支持从不同的数据源读取并写入不同的数据源
Pipeline & Processor
- pipeline,管道。会对通过的数据按照顺序进行加工。pipeline就是一组processor
- processor,对加工的行为进行抽象包装
Elasticsearch 有很多内置的Processors,也支持通过插件的方式,实现自己的Processor。
https://www.elastic.co/guide/en/elasticsearch/reference/7.17/ingest-processors.html
一些内置的Processors:
- Split Processor : 将给定字段值分成一个数组
- Remove / Rename Processor :移除一个重命名字段
- Append : 为商品增加一个新的标签
- Convert:将商品价格,从字符串转换成float 类型
- Date / JSON:日期格式转换,字符串转JSON对象
- Date lndex Name Processor︰将通过该处理器的文档,分配到指定时间格式的索引中
- Fail Processor︰一旦出现异常,该Pipeline 指定的错误信息能返回给用户
- Foreach Process︰数组字段,数组的每个元素都会使用到一个相同的处理器
- Grok Processor︰日志的日期格式切割
- Gsub / Join / Split︰字符串替换│数组转字符串/字符串转数组
- Lowercase / upcase︰大小写转换
案例,对文档中tags字段中的字符串使用逗号分隔,转换为一个数组字段
bash
# 测试 文档中tags字段中的字符串使用逗号分隔,转换为一个数组字段
# _simulate 关键字的作用是模拟,也就是模拟查看我们预处理的结果
POST /_ingest/pipeline/_simulate
{
"pipeline": {
"description": "描述信息,将tags字段按逗号分隔",
"processors": [
{
"split": { # 关键字split就表示对某个字段按某个字符进行拆分
"field": "tags",
"separator": ","
}
}
]
},
"docs": [ # 指定两个文档数据,这些文档就要经过上面的预处理
{
"_index": "index",
"_id": "1",
"_source": {
"title": "Introducing big data......",
"tags": "hadoop,elasticsearch,spark",
"content": "You konw, for big data"
}
},
{
"_index": "index",
"_id": "2",
"_source": {
"title": "Introducing cloud computering",
"tags": "openstack,k8s",
"content": "You konw, for cloud"
}
}
]
}
案例,为文档添加一个字段
bash
POST /_ingest/pipeline/_simulate
{
"pipeline": {
"description": "描述信息,将tags字段按逗号分隔",
"processors": [
{
"split": {
"field": "tags",
"separator": ","
}
},
{
"set": {
"field": "views",
"value": 0
}
}
]
},
"docs": [
{
"_index": "index",
"_id": "1",
"_source": {
"title": "Introducing big data......",
"tags": "hadoop,elasticsearch,spark",
"content": "You konw, for big data"
}
},
{
"_index": "index",
"_id": "2",
"_source": {
"title": "Introducing cloud computering",
"tags": "openstack,k8s",
"content": "You konw, for cloud"
}
}
]
}
案例:创建pipeline
在请求的url中就不要使用_simulate
模拟关键字了,直接指定一个自定义名字
bash
# 创建一个名称为 hs_blog_pipeline 的pipeline
PUT /_ingest/pipeline/hs_blog_pipeline
{
"description": "描述信息,将tags字段按逗号分隔",
"processors": [
{
"split": {
"field": "tags",
"separator": ","
}
},
{
"set": {
"field": "views",
"value": 0
}
}
]
}
# 查看上方创建的pipeline
GET /_ingest/pipeline
使用pipeline更新数据
在url请求路径中添加pipeline=自定义pipeline名
请求参数,表示当前创建的文档需要进行预处理
bash
# 不使用pipeline更新数据
PUT tech_blogs/_doc/1
{
"title":"Introducing big data......",
"tags":"hadoop,elasticsearch,spark",
"content":"You konw, for big data"
}
# 使用pipeline更新数据
PUT tech_blogs/_doc/2?pipeline=hs_blog_pipeline
{
"title": "Introducing cloud computering",
"tags": "openstack,k8s",
"content": "You konw, for cloud"
}
借助update_by_query
对符合条件的文档进行更新
bash
# 必须要POST请求
# 如果不加query查询语句会报错
POST /tech_blogs/_update_by_query?pipeline=hs_blog_pipeline
{
}
# 必须要POST请求
# 如果不加query查询语句会报错
# 对不存在views字段的文档进行 指定的预处理操作。此时,上方插入id=1的文档也进行了相关处理操作
POST /tech_blogs/_update_by_query?pipeline=hs_blog_pipeline
{
"query": {
"bool": {
"must_not": [
{
"exists": {
"field": "views"
}
}
]
}
}
}
painless script
painless支持所有java数据类型以及java api接口子集
用途:
-
可以对文档字段进行加工处理
- 更新、删除字段;处理数据聚合操作
- 对返回的字段提前进行处理 script field
- 对文档的相关性算分进行处理 function script
-
在ingest pipeline中执行java脚本
-
在
_reindex
API、_update_by_query
API时对数据进行处理
通过painless script脚本访问字段
上下文 | 语法 |
---|---|
Ingestion pipeline 语句中 | ctx.field_name |
Update 修改语句中 | ctx._source.field_name |
Search & Aggregation 搜索和聚合语句中 | doc["field_name"] |
在ingest pipeline中使用painless script
bash
# 新增了一个script,
POST /_ingest/pipeline/_simulate
{
"pipeline": {
"description": "描述信息,将tags字段按逗号分隔",
"processors": [
{
"split": {
"field": "tags",
"separator": ","
}
},
{
"set": {
"field": "views",
"value": 0
}
},
{
"script": { # 使用script关键字
"source": """ # 在source中进行java代码的编写,如果只有一条java语句就直接使用双引号,如果换行了就要在前后都加上"""三个
if(ctx.containsKey("content")){
ctx.hs_content_length = ctx.content.length(); #Ingestion pipeline 语句中 通过ctx.field_name语法获取文档字段
}else{
ctx.hs_content_length = 0;
}
"""
}
}
]
},
"docs": [
{
"_index": "index",
"_id": "1",
"_source": {
"title": "Introducing big data......",
"tags": "hadoop,elasticsearch,spark",
"content": "You konw, for big data"
}
},
{
"_index": "index",
"_id": "2",
"_source": {
"title": "Introducing cloud computering",
"tags": "openstack,k8s",
"content": "You konw, for cloud"
}
}
]
}
在update语句中使用 painless script
bash
DELETE tech_blogs
PUT tech_blogs/_doc/1
{
"title":"Introducing big data......",
"tags":"hadoop,elasticsearch,spark",
"content":"You konw, for big data",
"views":0
}
#
# 在uodate语句中,获取文档字段的方式为 ctx._source.field_name
POST /tech_blogs/_update/1
{
"script": {
"source": "ctx._source.views += params.new_views", # 通过params. 的方式使用下面定义的参数
"params": {
"new_views": 100 # 定义一个参数
}
}
}
# 第二种方式,将脚本保存后再使用 hs_update_views为自定义id
POST _scripts/hs_update_views
{
"script":{
"lang": "painless",
"source": "ctx._source.views += params.new_views"
}
}
POST tech_blogs/_update/1
{
"script": {
"id": "hs_update_views", # 指定上面我们自定义的id
"params": {
"new_views":1000
}
}
}
在搜索中使用painless script语句,一般不建议在搜索中使用painless script语句对字段值进行操作,这样降低了查询效率。预处理一般是新增文档时进行
bash
GET /tech_blogs/_search
{
"script_fields": {
"hs_rnd_views": {
"script": {
"lang": "painless",
"source": """
java.util.Random rnd = new Random();
doc['views'].value+rnd.nextInt(1000);
"""
}
}
},
"query": {
"match_all": {}
}
}