弹性搜索根据嵌套字段值应用提升
Elastic search apply boost based on nested field value
下面是我的索引文档
{
"defaultBoostValue":1.01,
"boostDetails": [
{
"Type": "Type1",
"value": 1.0001
},
{
"Type": "Type2",
"value": 1.002
},
{
"Type": "Type3",
"value": 1.0005
}
]
}
我想根据传递的值应用提升,所以假设我传递了类型 1,那么应用的提升将为 1.0001,如果该类型 1 不存在,那么它将使用 defaultBoostValue
下面是我的查询,它有效但速度很慢,有没有办法进一步优化它
上面的查询有效但速度很慢,因为我们正在使用 _source
{
"query": {
"function_score": {
"boost_mode": "multiply",
"functions": [
"script_score": {
"script": {
"source": """
double findBoost(Map params_copy) {
for (def group : params_copy._source.boostDetails) {
if (group['Type'] == params_copy.preferredBoostType ) {
return group['value'];
}
}
return params_copy._source['defaultBoostValue'];
}
return findBoost(params)
""",
"params": {
"preferredBoostType": "Type1"
}
}
}
}
]
}
}
}
我已经删除了没有动态映射的条件,如果更改 boostDetails 映射的结构可以帮助那么我没问题,但请解释它如何帮助并更快地查询也请提供映射类型和修改后的结构如果答案包含修改映射。
使用动态映射(很多字段)
与 相比,您似乎调整了文档结构。
上面的查询是针对嵌套字段考虑的,出于性能原因,这些字段不能轻易在脚本中迭代。话虽如此,以上是一个更慢的解决方法,它访问文档的 _source
并迭代其内容。但请记住,不推荐在脚本中访问 _source
!
如果您的文档不再嵌套,您可以访问所谓的 doc values,它针对查询时访问进行了更优化:
{
"query": {
"function_score": {
...
"functions": [
{
...
"script_score": {
"script": {
"lang": "painless",
"source": """
try {
if (doc['boost.boostType.keyword'].value == params.preferredBoostType) {
return doc['boost.boostFactor'].value;
} else {
throw new Exception();
}
} catch(Exception e) {
return doc['fallbackBoostFactor'].value;
}
""",
"params": {
"preferredBoostType": "Type1"
}
}
}
}
]
}
}
}
从而加快您的功能分数查询。
使用有序值列表的替代方法
由于嵌套迭代很慢并且动态映射会破坏您的索引,您可以将提升存储在每个文档中的标准化有序列表中:
"boostValues": [1.0001, 1.002, 1.0005, ..., 1.1]
并在构建查询的后端跟踪相应增强类型的顺序:
var boostTypes = ["Type1", "Type2", "Type3", ..., "TypeN"]
所以像 n-hot vectors.
然后,在构建 Elasticsearch 查询时,您将根据 boostType
查找 boostValues
的 数组索引 并传递此上面脚本查询的数组索引将访问相应的 boostValues
文档值。
这保证比 _source
访问速度更快。 但要求您始终保持 boostTypes
和 boostValues
同步 -- 最好仅附加(当您添加新的 boostTypes
时,列表在一维增长)。
下面是我的索引文档
{
"defaultBoostValue":1.01,
"boostDetails": [
{
"Type": "Type1",
"value": 1.0001
},
{
"Type": "Type2",
"value": 1.002
},
{
"Type": "Type3",
"value": 1.0005
}
]
}
我想根据传递的值应用提升,所以假设我传递了类型 1,那么应用的提升将为 1.0001,如果该类型 1 不存在,那么它将使用 defaultBoostValue 下面是我的查询,它有效但速度很慢,有没有办法进一步优化它
{
"query": {
"function_score": {
"boost_mode": "multiply",
"functions": [
"script_score": {
"script": {
"source": """
double findBoost(Map params_copy) {
for (def group : params_copy._source.boostDetails) {
if (group['Type'] == params_copy.preferredBoostType ) {
return group['value'];
}
}
return params_copy._source['defaultBoostValue'];
}
return findBoost(params)
""",
"params": {
"preferredBoostType": "Type1"
}
}
}
}
]
}
}
}
我已经删除了没有动态映射的条件,如果更改 boostDetails 映射的结构可以帮助那么我没问题,但请解释它如何帮助并更快地查询也请提供映射类型和修改后的结构如果答案包含修改映射。
使用动态映射(很多字段)
与
上面的查询是针对嵌套字段考虑的,出于性能原因,这些字段不能轻易在脚本中迭代。话虽如此,以上是一个更慢的解决方法,它访问文档的 _source
并迭代其内容。但请记住,不推荐在脚本中访问 _source
!
如果您的文档不再嵌套,您可以访问所谓的 doc values,它针对查询时访问进行了更优化:
{
"query": {
"function_score": {
...
"functions": [
{
...
"script_score": {
"script": {
"lang": "painless",
"source": """
try {
if (doc['boost.boostType.keyword'].value == params.preferredBoostType) {
return doc['boost.boostFactor'].value;
} else {
throw new Exception();
}
} catch(Exception e) {
return doc['fallbackBoostFactor'].value;
}
""",
"params": {
"preferredBoostType": "Type1"
}
}
}
}
]
}
}
}
从而加快您的功能分数查询。
使用有序值列表的替代方法
由于嵌套迭代很慢并且动态映射会破坏您的索引,您可以将提升存储在每个文档中的标准化有序列表中:
"boostValues": [1.0001, 1.002, 1.0005, ..., 1.1]
并在构建查询的后端跟踪相应增强类型的顺序:
var boostTypes = ["Type1", "Type2", "Type3", ..., "TypeN"]
所以像 n-hot vectors.
然后,在构建 Elasticsearch 查询时,您将根据 boostType
查找 boostValues
的 数组索引 并传递此上面脚本查询的数组索引将访问相应的 boostValues
文档值。
这保证比 _source
访问速度更快。 但要求您始终保持 boostTypes
和 boostValues
同步 -- 最好仅附加(当您添加新的 boostTypes
时,列表在一维增长)。