Elasticsearch:Painless scripting 高级编程

2021-01-08 16:14:33 浏览数 (1)

腾讯云 Elasticsearch Service】高可用,可伸缩,云端全托管。集成X-Pack高级特性,适用日志分析/企业搜索/BI分析等场景


在之前的文章中,我介绍了 Painless 脚本编程,并提供了有关其语法和用法的详细信息。 它还涵盖了一些最佳实践,例如,为什么使用参数,何时访问文档字段时何时使用 “doc” 值而不是 “ _source” 以及如何动态创建字段等。

之前的文章:

  • Elasticsearch:Painless scripting
  • Elasticsearch: Painless script编程

在本文中,我们将探讨 Painless 脚本的更多用法。 本文介绍了在查询上下文中使用 Painless 脚本,过滤上下文,在脚本中使用条件,删除字段/嵌套字段,访问嵌套对象,在评分中使用脚本等。

教程

首先,让我们使用可用于本文其余部分的数据集:

代码语言:javascript复制
PUT tweets/_bulk{"index":{"_id":1}}{"username":"tom","posted_date":"2017/07/25" ,"message": "I brought apple stock at the best price" ,"tags": ["stock","money"] , "info":{"device":"mobile", "os": "ios"}, "likes": 10}{"index":{"_id":2}}{"username":"mary","posted_date":"2017/06/25" ,"message": "Machine learning is the future" ,"tags": ["ai","tech"] , "info":{"device":"desktop", "os": "ios"}, "likes": 100}{"index":{"_id":3}}{"username":"tom","posted_date":"2017/07/27" ,"message": "just tweeting" ,"tags": ["confused"] , "info":{"device":"mobile", "os": "win"}, "likes": 0}{"index":{"_id":4}}{"username":"mary","posted_date":"2017/07/28" ,"message": "exploring painless" ,"tags": ["elastic"] , "info":{"device":"mobile", "os": "linux"}, "likes": 100}{"index":{"_id":5}}{"username":"mary","posted_date":"2017/05/20" ,"message": "painless is fun but its a new scripting language in the town" ,"tags": ["elastic","painless","scripting"] , "info":{"device":"mobile", "os": "linux"}, "likes": 1000}

在上面,我们通过 bulk API 来把我们的实验数据导入到 tweets 索引中。

Script Query

脚本查询使我们可以在每个文档上执行脚本。 脚本查询通常在过滤器上下文中使用。 如果要在查询或过滤器上下文中包含脚本,请确保将脚本嵌入脚本对象("script":{})中。 因此,在下面的示例中,您将在 script 标签内看到 script 标签。

让我们尝试一个例子。 让我们找出所有包含字符串 “painless” 且长度大于25个字符的推文。

代码语言:javascript复制
GET tweets/_search{  "query": {    "bool": {      "must": [        {          "match": {            "message": "painless"          }        }      ],      "filter": [        {          "script": {            "script": {              "source": "doc['message.keyword'].value.length() > params.length",              "params": {                "length": 25              }            }          }        }      ]    }  }}

返回结果:

代码语言:javascript复制
    "hits" : [      {        "_index" : "tweets",        "_type" : "_doc",        "_id" : "5",        "_score" : 0.60910475,        "_source" : {          "username" : "mary",          "posted_date" : "2017/05/20",          "message" : "painless is fun but its a new scripting language in the town",          "tags" : [            "elastic",            "painless",            "scripting"          ],          "info" : {            "device" : "mobile",            "os" : "linux"          },          "likes" : 1000        }      }    ]

Aggregation 中的 Scripts

脚本也可以用于聚合中。 对于聚合,我们通常使用字段(非分析字段)中的值执行聚合。 使用脚本,可以从现有字段中提取值,从多个字段中追加值,然后对新派生的值进行聚合。

在上面的推文中,我们仅包含 “posted_date” 信息。 如果我们想找出每月的推文数量怎么办? 下面是一个示例,显示了聚合中脚本的使用:

代码语言:javascript复制
GET tweets/_search{  "size": 0,  "aggs": {    "my_terms_agg": {      "terms": {        "script": {          "source": """            ZonedDateTime date = doc['posted_date'].value;            return date.getMonth()         """        }      }    }  }}

在上面我们通过 script 来获得每个文档的月份,然后让这个生产的月份来进行做聚合:

代码语言:javascript复制
  "aggregations" : {    "my_terms_agg" : {      "doc_count_error_upper_bound" : 0,      "sum_other_doc_count" : 0,      "buckets" : [        {          "key" : "JULY",          "doc_count" : 3        },        {          "key" : "JUNE",          "doc_count" : 1        },        {          "key" : "MAY",          "doc_count" : 1        }      ]    }  }

使用脚本来删除一个字段

我们可以使用脚本删除字段/嵌套字段。 您要做的就是使用 remove 方法并传入字段/嵌套字段名称。 例如,假设我们要删除 ID 为5的文档的嵌套字段 “device”。

代码语言:javascript复制
POST tweets/_update/5{  "script": {    "source": "ctx._source.info.remove(params.fieldname)",    "params": {      "fieldname": "device"    }  }}

我们来重新查询id为5的文档:

代码语言:javascript复制
GET tweets/_doc/5

返回的结果:

代码语言:javascript复制
  "_source" : {    "username" : "mary",    "posted_date" : "2017/05/20",    "message" : "painless is fun but its a new scripting language in the town",    "tags" : [      "elastic",      "painless",      "scripting"    ],    "info" : {      "os" : "linux"    },    "likes" : 1000  }

我们可以看到在 info 下的 device 被删除了。

利用 Scripts 来定制分数

当我们执行匹配查询时,elasticsearch 返回匹配结果,并为每个匹配的文档计算分数,以显示文档与给定查询的匹配程度。 尽管默认算法 BM25 很好地完成了评分/相关性,但有时必须通过其他算法来回答相关性问题,或者必须通过其他评分启发式方法来增强相关性。 在这里,Elasticsearch 的 script_score 和 function_score 功能变得有用。

假设我们要搜索 “painless” 文本,但要在搜索结果顶部显示带有更多 “likes” 赞的推文。 它更像是顶部的热门推文/流行推文。 让我们来看看它的实际效果。

代码语言:javascript复制
GET tweets/_search{  "query": {    "function_score": {      "query": {        "match": {          "message": "painless"        }      },      "script_score": {        "script": {          "source": "1   doc['likes'].value"        }      }    }  }}

返回结果:

代码语言:javascript复制
        "hits" : [      {        "_index" : "tweets",        "_type" : "_doc",        "_id" : "5",        "_score" : 529.9271,        "_source" : {          "username" : "mary",          "posted_date" : "2017/05/20",          "message" : "painless is fun but its a new scripting language in the town",          "tags" : [            "elastic",            "painless",            "scripting"          ],          "info" : {            "os" : "linux"          },          "likes" : 1000        }      },      {        "_index" : "tweets",        "_type" : "_doc",        "_id" : "4",        "_score" : 98.51341,        "_source" : {          "username" : "mary",          "posted_date" : "2017/07/28",          "message" : "exploring painless",          "tags" : [            "elastic"          ],          "info" : {            "device" : "mobile",            "os" : "linux"          },          "likes" : 100        }      }    ]

在上面的示例中,如果由于进行了常规查询而未创建自定义分数,则由于 TF/IDF,文档4将会位于顶部(由于这个句子比较短),也就是文档分数将高于文档5。

代码语言:javascript复制
GET tweets/_search{  "query": {    "match": {      "message": "painless"    }  }}

返回的结果是:

代码语言:javascript复制
    "hits" : [      {        "_index" : "tweets",        "_type" : "_doc",        "_id" : "4",        "_score" : 0.9753803,        "_source" : {          "username" : "mary",          "posted_date" : "2017/07/28",          "message" : "exploring painless",          "tags" : [            "elastic"          ],          "info" : {            "device" : "mobile",            "os" : "linux"          },          "likes" : 100        }      },      {        "_index" : "tweets",        "_type" : "_doc",        "_id" : "5",        "_score" : 0.5293977,        "_source" : {          "username" : "mary",          "posted_date" : "2017/05/20",          "message" : "painless is fun but its a new scripting language in the town",          "tags" : [            "elastic",            "painless",            "scripting"          ],          "info" : {            "os" : "linux"          },          "likes" : 1000        }      }    ]

文档id为4的分数高于 id 为5的文档。


最新活动

包含文章发布时段最新活动,前往ES产品介绍页,可查找ES当前活动统一入口

Elasticsearch Service自建迁移特惠政策>>

Elasticsearch Service 新用户特惠狂欢,最低4折首购优惠 >>

Elasticsearch Service 企业首购特惠,助力企业复工复产>>

关注“腾讯云大数据”公众号,技术交流、最新活动、服务专享一站Get~

0 人点赞