如何在Elasticsearch中对嵌套字段进行脚本排序?

4

我正在处理类似下面这样的文档:

{
  "product_name": "abc",
  "prices": {
    "regular": 9.99,
    "pricing_tables": [
     { "id": 1, "price": 8.99 },
     { "id": 2, "price": 7.99 }
    ]
  }
}

prices.pricing_tables是一个嵌套的字段。

我想要做的是按照以下逻辑排序,给定一个价格表id:

  • 如果嵌套字段包含给定的id,则使用pricing_tables.price
  • 如果嵌套字段不包含id,则使用prices.regular

到目前为止我尝试使用的查询语句:

"sort": [
{
  "_script": {
    "type": "number",
    "script": {
      "lang": "painless",
      "source": """
        if(doc['prices.pricing_tables.price'].size() != 0) { 
          return doc['prices.pricing_tables.price'].value; 
        } 
        else {
          return doc['prices.regular'].value;
        }
        """
    },
    "nested": {
      "path": "prices.pricing_tables",
      "filter": {
        "term": {"prices.pricing_tables.id": 1}
      }
    },
    "order": "asc"
  }
}  
]

然而,它并没有按照预期的方式工作。当定价表嵌套对象中没有条目时,结果中的排序值总是1.7976931348623157E308。

我在这里错过了什么?是否可能实现这个功能?


你最终解决了这个问题吗? - Shirkan
2个回答

1

你的嵌套过滤器本质上是排除了所有pricing_tables.id不等于1的文档。然后Elasticsearch将这些文档分配给排序值1.79E308。这个数字不是随机的--它确实是Double.MAX_VALUE,在asc排序的情况下,ES会默认使用它。

但回到你的脚本排序。我认为你不能轻松地访问prices.pricing_tables.price的文档值,而不使prices本身成为nested

你可以做的是:

  • 作为HashMap访问底层的_source
  • 迭代pricing_tables(如果适用)
  • 退回到常规价格

以下是一个例子:

{
  "sort": [
    {
      "_script": {
        "type": "number",
        "script": {
          "lang": "painless",
          "params": {
            "table_id": 1
          },
          "source": """
            def regular = doc['prices.regular'].value;
            def raw_prices = params._source['prices']['pricing_tables'];
          
            if (raw_prices.length != 0) { 
              for (def pair : raw_prices) {
                if (pair['id'] == params.table_id) {
                  return pair['price'];
                }
              }
              return regular; 
            }
            
            return regular;
          """
        },
        "order": "asc"
      }
    }
  ]
}

请记住,访问_source会使您的排序性能不佳,而访问文档值则更为高效。

0
我找到的解决方案是根本不使用脚本排序。
我在带有 ID 0 的 pricing_tables 嵌套字段中添加了常规价格。除此之外,我还添加了一个包含其他 pricing_tables 的 ID 数组。
例如,如果我需要使用特定的 pricing_tables 值进行排序,我会使用:
{
  "prices.pricing_tables.price": {
    "mode": "min",
    "order": "asc",
    "nested": {
      "path": "prices.pricing_tables",
      "filter": {
        "bool": {
          "should": [
            {
              "term": {
                "prices.pricing_tables.id": 1
              }
            },
            {
              "bool": {
                "must": {
                  "term": {
                    "prices.pricing_tables.id": 0
                  }
                },
                "must_not": {
                  "term": {
                    "prices.pricing_tables.other_tables": 1
                  }
                }
              }
            }
          ]
        }
      }
    }
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接