当前位置: 首页 > 面试题库 >

如何在Elasticsearch脚本中访问嵌套数组的doc值?

沈凯康
2023-03-14
问题内容

给定以下索引,我如何在嵌套数组中选择适当的项目并访问其中的一个值?目的是在内的值中使用它script_score

# Create mapping
curl -XPUT localhost:9200/test/user/_mapping -d '
{
  "user" : {
    "properties" : {
      "name" : {
        "type" : "string"
      },
      "skills" : {
        "type": "nested", 
        "properties" : {
          "skill_id" : {
            "type" : "integer"
          },
          "recommendations_count" : {
            "type" : "integer"
          }
        }
      }
    }
  }
}
'

# Indexing Data
curl -XPUT localhost:9200/test/user/1 -d '
{
   "name": "John",
   "skills": [
      {
         "skill_id": 100,
         "recommendations_count": 5
      },
      {
         "skill_id": 200,
         "recommendations_count": 3
      }
   ]
}
'

curl -XPUT localhost:9200/test/user/2 -d '
{
   "name": "Mary",
   "skills": [
      {
         "skill_id": 100,
         "recommendations_count": 9
      },
      {
         "skill_id": 200,
         "recommendations_count": 0
      }
   ]
}
'

我的查询按skill_id过滤,效果很好。然后,我希望能够 针对给定的skill_id
使用更高script_score的分数来提高user文档的分数recommendations_count (<-这是关键)。

curl -XPOST localhost:9200/test/user/_search -d '
{      
    "query":{
      "function_score":{
        "query":{
          "bool":{
            "must":{
              "nested":{
                "path":"skills",
                "query":{
                  "bool":{
                    "must":{
                      "term":{
                        "skill_id":100
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "functions":[
          {
            "script_score": {
               "script": "sqrt(1.2 * doc['skills.recommendations_count'].value)"   
            }
          }            
        ]
      }
    }
  }
} 
'

如何skills从中访问数组,在数组中script找到’skill_id:100’项目,然后使用其recommendations_count值?在script_score上述目前不工作(比分始终是0,而不管数据的,所以我想doc['skills.recommendations_count'].value在正确的地方是不看。


问题答案:

对于您的特定问题,脚本需要嵌套上下文,就像您对term查询所做的一样。

可以为ES 1.x重写:

curl -XGET 'localhost:9200/test/_search' -d'
{
  "query": {
    "nested": {
      "path": "skills",
      "query": {
        "filtered": {
          "filter": {
            "term": {
              "skills.skill_id": 100
            }
          },
          "query": {
            "function_score": {
              "functions": [
                {
                  "script_score": {
                    "script": "sqrt(1.2 * doc['skills.recommendations_count'].value)"
                  }
                }
              ]
            }
          }
        }
      }
    }
  }
}'

对于ES 2.x(过滤器在ES 2.x中成为一等公民,因此语法进行了一些更改以跟上!):

curl -XGET 'localhost:9200/test/_search' -d'
{
  "query": {
    "nested": {
      "path": "skills",
      "query": {
        "bool": {
          "filter": {
            "term": {
              "skills.skill_id": 100
            }
          },
          "must": {
            "function_score": {
              "functions": [
                {
                  "script_score": {
                    "script": "sqrt(1.2 * doc['skills.recommendations_count'].value)"
                  }
                }
              ]
            }
          }
        }
      }
    }
  }
}'

注意:我使term查询成为term过滤器,因为它对分数没有逻辑影响(无论是完全匹配还是不完全匹配)。我还将嵌套字段的名称添加到了term过滤器中,这是Elasticsearch
2.x和更高版本(以及先前的良好实践)的要求。

这样一来,您就可以( 并且
应该)避免尽可能使用脚本。这是其中一种情况。function_score支持field_value_factor功能的概念,该功能使您可以完全按照自己的尝试去做,但完全不需要脚本。您还可以选择提供一个“
missing”值来控制如果缺少该字段会发生什么。

这将转换为 完全相同 的脚本,但是会表现得更好:

curl -XGET 'localhost:9200/test/_search' -d'
{
  "query": {
    "nested": {
      "path": "skills",
      "query": {
        "filtered": {
          "filter": {
            "term": {
              "skills.skill_id": 100
            }
          },
          "query": {
            "function_score": {
              "functions": [
                {
                  "field_value_factor": {
                    "field": "skills.recommendations_count",
                    "factor": 1.2,
                    "modifier": "sqrt",
                    "missing": 0
                  }
                }
              ]
            }
          }
        }
      }
    }
  }
}'

对于ES 2.x:

curl -XGET 'localhost:9200/test/_search' -d'
{
  "query": {
    "nested": {
      "path": "skills",
      "query": {
        "bool": {
          "filter": {
            "term": {
              "skills.skill_id": 100
            }
          },
          "must": {
            "function_score": {
              "functions": [
                {
                  "field_value_factor": {
                    "field": "skills.recommendations_count",
                    "factor": 1.2,
                    "modifier": "sqrt",
                    "missing": 0
                  }
                }
              ]
            }
          }
        }
      }
    }
  }
}'

脚本很慢,并且 暗示着Elasticsearch
1.x中使用fielddata,这很糟糕。您确实提到了doc值,这是一个有希望的开端,它表明使用Elasticsearch 2.x,但这可能只是术语。

如果您只是从Elasticsearch开始,那么我强烈建议从最新版本开始。



 类似资料:
  • 问题内容: 我有一个存储在ElasticSearch中的文档,如下所示。_资源: 我可以使用脚本化的指标汇总 http://www.elasticsearch.org/guide/zh- CN/elasticsearch/reference/current/search-aggregations-metrics-scripted- metric- aggregation.html访问 文档中的字符

  • 问题内容: 我在elasticsearch中的索引具有以下映射: 源文档如下: 我正在尝试使用距离脚本来基于地理点计算距离。我在elasticsearch结果中发现了该帖子的Return distance吗?帮我 我正在尝试获取所有结果,按半径1km进行过滤,获取距离,然后对geo_point进行排序。查询的结构如下: 我收到状态为500的以下错误: 我尝试以这种方式重写查询: 然后我得到这个错误

  • 我需要在嵌套字段上应用一个脚本,在那里我可以遍历用户数组。 例如,我尝试了以下方法: 我得到这个错误

  • 我想从特定字段中搜索关键字并返回文档。在这些文档之上,我希望遍历每个嵌套对象,并从选定文档的同一特定字段中再次搜索关键字。 如果关键字存在,则检查:如果布尔isCurrent = True,则设置isCurrent=0,并将该值追加到列表中;否则,如果isCurrent = False,则取当前日期时间的差值,结束日期时间,并获得以月为单位的值,并将该值追加到列表中。 最后,从每个文档的列表中获取

  • 我有以下文件: 第一份文件: 第二份文件: 我知道如果我想按产品名称分组,我可以使用聚合 这将给我两个桶,两个不同的键“product1”,“product2”。 但是,如果我想按标记键分组,查询应该是什么?i、 e.我想按name==key1的标记分组,然后我希望有一个key=“value1”的bucket;而如果我按name==key2的标记分组,我希望结果是两个bucket,其键为“valu

  • 问题内容: 我有一个Java的HashMap,其内容(大家可能都知道)可以由 如果在另一个HashMap中有一个HashMap,即嵌套的HashMap,我将如何访问内容?我可以这样做吗,内联: 谢谢。 问题答案: 您可以像假设的那样进行操作。但是您的HashMap必须模板化: 否则,从第一张地图检索第二张地图后,您必须进行强制转换。