沙师弟,师父的充电器掉了
painless

painless

在script_score使用doc['date']排序出错

回复

Elasticsearchhubiao 回复了问题 • 1 人关注 • 1 个回复 • 3753 次浏览 • 2020-01-15 21:22 • 来自相关话题

elasticsearch painless 如何获取text类型的数据

ElasticsearchGod_lockin 回复了问题 • 2 人关注 • 1 个回复 • 5551 次浏览 • 2020-01-15 18:19 • 来自相关话题

ES脚本性能优化一例

Elasticsearchhufuman 发表了文章 • 0 个评论 • 5926 次浏览 • 2019-11-13 19:48 • 来自相关话题

使用painless脚本为文档自定义打分是很常见的场景,对新人来说也是最容易造成性能问题的地方。本文中使用两个例子简单谈一下脚本性能优化。

目标

ES本身是基于倒排等数据结构实现的查询,因此在做类似Term、Match等可以利用底层数据结构的场景进行查询时,性能是很好的。

脚本和term等查询不一样,无法利用现有的各种数据结构,可以简单理解成循环:

docs = getDocs(xxx); // 获取满足条件的文档列表
for(Doc doc : docs) {
    score = getScoreByScript(doc);
}

因此脚本的性能取决于两个地方:脚本的复杂度和满足条件的文档数

例子1

我们有个场景是查询指定坐标指定范围内的POI列表,例如5公里内的景点列表。

由于我们的距离公式和ES默认的都不一致,如下:

/**
 * 计算距离,返回单位:米
 */
public static Double getDistance(Double lat1, Double lng1, Double lat2, Double lng2) {
    double diffLon = Math.abs(lng1 - lng2);
    if (diffLon > 180)
        diffLon -= 360;
    return Math.sqrt(Math.pow(diffLon, 2) + Math.pow(lat1 - lat2, 2)) * 110.0 * 1000;
}

所以该同学把这段Java代码转成了Painless,在sort里使用这个该方法计算出距离。上线以后发现ES有了很多慢查询,对应的服务也95线、99线也比较高。

原因是其他脚本没有有效地缩小数据量,导致有几百万的数据需要使用该脚本做距离计算,给ES的CPU造成很大压力,查询性能也比较差。

该例子优化起来很简单,即使用ES自带的distance做较大范围的限制,例如需要5公里的数据,可以用ES的plain距离做限制,再加上之前的自定义脚本逻辑。由于ES的plain距离计算性能好很多,因此经过该过滤以后,自定义脚本的文档量少了很多,因此整体性能有了很大提升。

例子2

有个场景是对文章进行搜索,如果文章关联的城市是指定的几个城市,则给额外的加分。例如:

{
    "query": {xxx},
    "sort": [
    {
      "_script": {
        "script": {
          "source": "def score = 0;def cityIds = doc['cityIds']; def paramCityIds = params.cityIds; for (int i=0; i<cityIds.size(); i++){if (paramCityIds.contains(cityIds[i])){score += 100;}} return score;",
          "lang": "painless",
          "params": {
            "cityIds": [2,1,3]
          }
        },
        "type": "number",
        "order": "desc"
      }
    }
    ]
}

问题和例子1一样,该功能的性能比较差。虽然脚本简单,但是满足的文档量比较大,带来的计算量也比较多,因此性能上不去。

这是一个比较常见的场景,问题的根源还是对ES的机制不够了解,优化起来也很简单,想办法利用到倒排就可以了。

ES里有个专门针对改场景的查询:constant_score,因此以上查询可以修改为:

{
    "query": {
        "should": [
            {
                    "constant_score": {
                        "filter": {
                            "term": {
                                    "cityIds": 2
                            }
                        },
                        "boost": 5
                     }
            },
            {
                    "constant_score": {
                        "filter": {
                            "term": {
                                    "cityIds": 1
                            }
                        },
                        "boost": 5
                     }
            },
            {
                    "constant_score": {
                        "filter": {
                            "term": {
                                    "cityIds": 3
                            }
                        },
                        "boost": 5
                     }
            }
        ]
    },
    "sort": [
    {
      "_score": "desc"
    ]
}

性能即可得到极大改善。

painless 怎么 parse json to map

Elasticsearchdoom 回复了问题 • 2 人关注 • 3 个回复 • 4305 次浏览 • 2019-10-08 02:40 • 来自相关话题

elasticsearch利用script获取nested类型数据并计算怎么实现?

Elasticsearchlaoyang360 回复了问题 • 5 人关注 • 2 个回复 • 7870 次浏览 • 2019-07-30 21:29 • 来自相关话题

es是否支持在script中进行更新的同时返回其中某项计算值

Elasticsearchhufuman 回复了问题 • 2 人关注 • 1 个回复 • 4642 次浏览 • 2019-07-24 19:37 • 来自相关话题

painless中如何判断一个字段是否存在

Elasticsearchrochy 回复了问题 • 2 人关注 • 1 个回复 • 5889 次浏览 • 2018-12-04 13:38 • 来自相关话题

在script_score使用doc['date']排序出错

回复

Elasticsearchhubiao 回复了问题 • 1 人关注 • 1 个回复 • 3753 次浏览 • 2020-01-15 21:22 • 来自相关话题

elasticsearch painless 如何获取text类型的数据

回复

ElasticsearchGod_lockin 回复了问题 • 2 人关注 • 1 个回复 • 5551 次浏览 • 2020-01-15 18:19 • 来自相关话题

painless 怎么 parse json to map

回复

Elasticsearchdoom 回复了问题 • 2 人关注 • 3 个回复 • 4305 次浏览 • 2019-10-08 02:40 • 来自相关话题

elasticsearch利用script获取nested类型数据并计算怎么实现?

回复

Elasticsearchlaoyang360 回复了问题 • 5 人关注 • 2 个回复 • 7870 次浏览 • 2019-07-30 21:29 • 来自相关话题

es是否支持在script中进行更新的同时返回其中某项计算值

回复

Elasticsearchhufuman 回复了问题 • 2 人关注 • 1 个回复 • 4642 次浏览 • 2019-07-24 19:37 • 来自相关话题

painless中如何判断一个字段是否存在

回复

Elasticsearchrochy 回复了问题 • 2 人关注 • 1 个回复 • 5889 次浏览 • 2018-12-04 13:38 • 来自相关话题

ES脚本性能优化一例

Elasticsearchhufuman 发表了文章 • 0 个评论 • 5926 次浏览 • 2019-11-13 19:48 • 来自相关话题

使用painless脚本为文档自定义打分是很常见的场景,对新人来说也是最容易造成性能问题的地方。本文中使用两个例子简单谈一下脚本性能优化。

目标

ES本身是基于倒排等数据结构实现的查询,因此在做类似Term、Match等可以利用底层数据结构的场景进行查询时,性能是很好的。

脚本和term等查询不一样,无法利用现有的各种数据结构,可以简单理解成循环:

docs = getDocs(xxx); // 获取满足条件的文档列表
for(Doc doc : docs) {
    score = getScoreByScript(doc);
}

因此脚本的性能取决于两个地方:脚本的复杂度和满足条件的文档数

例子1

我们有个场景是查询指定坐标指定范围内的POI列表,例如5公里内的景点列表。

由于我们的距离公式和ES默认的都不一致,如下:

/**
 * 计算距离,返回单位:米
 */
public static Double getDistance(Double lat1, Double lng1, Double lat2, Double lng2) {
    double diffLon = Math.abs(lng1 - lng2);
    if (diffLon > 180)
        diffLon -= 360;
    return Math.sqrt(Math.pow(diffLon, 2) + Math.pow(lat1 - lat2, 2)) * 110.0 * 1000;
}

所以该同学把这段Java代码转成了Painless,在sort里使用这个该方法计算出距离。上线以后发现ES有了很多慢查询,对应的服务也95线、99线也比较高。

原因是其他脚本没有有效地缩小数据量,导致有几百万的数据需要使用该脚本做距离计算,给ES的CPU造成很大压力,查询性能也比较差。

该例子优化起来很简单,即使用ES自带的distance做较大范围的限制,例如需要5公里的数据,可以用ES的plain距离做限制,再加上之前的自定义脚本逻辑。由于ES的plain距离计算性能好很多,因此经过该过滤以后,自定义脚本的文档量少了很多,因此整体性能有了很大提升。

例子2

有个场景是对文章进行搜索,如果文章关联的城市是指定的几个城市,则给额外的加分。例如:

{
    "query": {xxx},
    "sort": [
    {
      "_script": {
        "script": {
          "source": "def score = 0;def cityIds = doc['cityIds']; def paramCityIds = params.cityIds; for (int i=0; i<cityIds.size(); i++){if (paramCityIds.contains(cityIds[i])){score += 100;}} return score;",
          "lang": "painless",
          "params": {
            "cityIds": [2,1,3]
          }
        },
        "type": "number",
        "order": "desc"
      }
    }
    ]
}

问题和例子1一样,该功能的性能比较差。虽然脚本简单,但是满足的文档量比较大,带来的计算量也比较多,因此性能上不去。

这是一个比较常见的场景,问题的根源还是对ES的机制不够了解,优化起来也很简单,想办法利用到倒排就可以了。

ES里有个专门针对改场景的查询:constant_score,因此以上查询可以修改为:

{
    "query": {
        "should": [
            {
                    "constant_score": {
                        "filter": {
                            "term": {
                                    "cityIds": 2
                            }
                        },
                        "boost": 5
                     }
            },
            {
                    "constant_score": {
                        "filter": {
                            "term": {
                                    "cityIds": 1
                            }
                        },
                        "boost": 5
                     }
            },
            {
                    "constant_score": {
                        "filter": {
                            "term": {
                                    "cityIds": 3
                            }
                        },
                        "boost": 5
                     }
            }
        ]
    },
    "sort": [
    {
      "_score": "desc"
    ]
}

性能即可得到极大改善。