lucene 在script_score中使用嵌套值

yk9xbfzb  于 2022-11-07  发布在  Lucene
关注(0)|答案(2)|浏览(197)

我尝试在脚本评分中使用嵌套值,但无法正常工作,因为我无法通过doc访问字段来遍历字段。此外,当我尝试在Kibana(如_type:images AND _exists_:colors)中查询它时,它将不匹配任何文档,即使当我单独查看所有文档时,该字段在所有文档中都清晰可见,但是我可以使用params._source来访问它,但是我读过,它可以很慢很慢,并不是真的推荐。
我知道这个问题完全是由于我们创建这个嵌套字段的方式造成的,所以如果我不能找到比这更好的方法,我将不得不重新索引我们的2 m+文档,看看我是否能找到另一种解决问题的方法,但我希望避免这种情况,同时也只是更好地理解Elastic在幕后是如何工作的,以及为什么它会以这种方式工作。
我在这里提供的例子并不是我的真实的生活问题,但也描述了这个问题。假设我们有一个描述图像的文档。该文档有一个字段,其中包含图像中存在多少红色、蓝色和绿色的值。
创建索引和文档的请求,这些文档具有包含颜色数组的嵌套字段,这些颜色数组之间以100磅分隔:

PUT images
{
  "settings": {
    "number_of_shards": 1
  },
  "mappings": {
    "_doc": {
      "properties": {
        "id" : { "type" : "integer" },
        "title" : { "type" : "text" },
        "description" : { "type" : "text" },
        "colors": {
          "type": "nested",
          "properties": {
            "red": {
              "type": "double"
            },
            "green": {
              "type": "double"
            },
            "blue": {
              "type": "double"
            }
          }
        }
      }
    }
  }
}

PUT images/_doc/1
{
    "id" : 1,
    "title" : "Red Image",
    "description" : "Description of Red Image",
    "colors": [
      {
        "red": 100
      },
      {
        "green": 0
      },
      {
        "blue": 0
      }
    ]
}

PUT images/_doc/2
{
    "id" : 2,
    "title" : "Green Image",
    "description" : "Description of Green Image",
    "colors": [
      {
        "red": 0
      },
      {
        "green": 100
      },
      {
        "blue": 0
      }
    ]
}

PUT images/_doc/3
{
    "id" : 3,
    "title" : "Blue Image",
    "description" : "Description of Blue Image",
    "colors": [
      {
        "red": 0
      },
      {
        "green": 0
      },
      {
        "blue": 100
      }
    ]
}

现在,如果我使用doc运行此查询:

GET images/_search
{
  "query": {
    "function_score": {
      "functions": [
        {
          "script_score": {
            "script": {
              "source": """
                boolean debug = true;
                for(color in doc["colors"]) {
                  if (debug === true) {
                    throw new Exception(color["red"].toString());
                  }
                }
              """
            }
          }
        }
      ]
    }
  }
}

我将得到异常No field found for [colors] in mapping with types [],但如果我使用params._source,如下所示:

GET images/_search
{
  "query": {
    "function_score": {
      "functions": [
        {
          "script_score": {
            "script": {
              "source": """
                boolean debug = true;
                for(color in params._source["colors"]) {
                  if (debug === true) {
                    throw new Exception(color["red"].toString());
                  }
                }
              """
            }
          }
        }
      ]
    }
  }
}

我可以输出"caused_by": {"type": "exception", "reason": "100"},所以我知道它工作了,因为第一个文档是红色的,值为100。
我甚至不确定这是否属于一个问题,但更多的是一种求助。如果有人能解释为什么会这样,并给予解决问题的最佳方法,我将非常感激。

(另外,一些在Painless中调试的技巧也会很棒!!!)

mf98qq94

mf98qq941#

在Elasticsearch的评分脚本"script_score": {"script": {"source": "..." }}中,您可以使用param._source对象访问嵌套值。
例如,如果您的documents索引包含以下文档:

{
  "title": "Yankees Potential Free Agent Target: Max Scherzer",
  "body": "...",
  "labels": {
    "genres": "news",
    "topics": ["sports", "celebrities"]
    "publisher": "CNN"
  }
}

下面的查询将以随机顺序返回100个文档,优先选择主题为sports的文档:

GET documents/_search
{
  "size": 100,
  "sort": [
    "_score"
  ],
  "query": {
    "function_score": {
      "query": { "match_all": {} },
      "functions": [
        {
          "random_score": {}
        },
        {
          "script_score": {
            "script": {
              "source": """
                double boost = 1.0;
                if (params._source['labels'] != null && params._source['labels']['topics'] != null && params._source['labels']['topics'].contains('sports') {
                    boost += 2.0;
                }
                return boost;
              """
            }
          }
        }
      ],
      "score_mode": "multiply",
      "boost_mode": "replace"
    }
  }
}
aor9mmx1

aor9mmx12#

不要担心params._source的速度慢'-这是您唯一的选择,因为迭代doc的嵌套上下文只允许访问单个嵌套颜色。
试试看:

GET images/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "title": "image"
          }
        },
        {
          "function_score": {
            "functions": [
              {
                "script_score": {
                  "script": {
                    "source": """
                        def score = 0;
                        for (color in params._source["colors"]) {
                          // Debug.explain(color);
                          if (color.containsKey('red')) {
                            score += color['red'] ;
                          }
                        }
                        return score;
                    """
                  }
                }
              }
            ]
          }
        }
      ]
    }
  }
}

无痛评分上下文为here
第二,您已经非常接近手动抛出异常了--不过有一种更干净的方法可以做到这一点。取消注解Debug.explain(color);,您就可以开始了。
还有一件事,我特意添加了一个match查询来提高分数,但更重要的是,为了说明查询是如何在后台构建的--当您在GET images/_validate/query?explain下重新运行上面的查询时,您将亲眼看到。

相关问题