1

我正在尝试过滤嵌套过滤对象中的属性总和在某个范围内的产品。

我有以下映射:

{
  "product": {
    "properties": {
      "warehouses": {
        "type": "nested",
        "properties": {
          "stock_level": {
            "type": "integer"
          }
        }
      }
    }
  }
}

示例数据:

{
  "id": 1,
  "warehouses": [
    {
      "id": 2001,
      "stock_level": 5
    },
    {
      "id": 2002,
      "stock_level": 0
    },
    {
      "id": 2003,
      "stock_level": 2
    }
  ]
}

在 ElasticSearch 5.6 中,我曾经这样做过:

GET products/_search
{
  "query": {
    "bool": {
      "filter": [
        [
          {
            "script": {
              "script": {
                "source": """
int total = 0;
for (def warehouse: params['_source']['warehouses']) {
  if (params.warehouse_ids == null || params.warehouse_ids.contains(warehouse.id)) {
    total += warehouse.stock_level;
  }
}
boolean gte = true;
boolean lte = true;
if (params.gte != null) {
  gte = (total >= params.gte);
}
if (params.lte != null) {
  lte = (total <= params.lte);
}
return (gte && lte);

""",
                "lang": "painless",
                "params": {
                  "gte": 4
                }
              }
            }
          }
        ]
      ]
    }
  }
}

问题是它params['_source']['warehouses']不再适用于 ES 6.8,而且我无法找到访问脚本中嵌套文档的方法。

我努力了:

  • doc['warehouses']- 返回错误(“在类型为 [] 的映射中未找到 [仓库] 的字段”)
  • ctx._source.warehouses- “变量 [ctx] 未定义。”</li>

我也尝试过使用 scripted_field,但似乎脚本字段是在最后阶段计算的,并且在查询期间不可用。

我也按照相同的逻辑进行排序(按给定仓库中的库存总和对产品进行排序),它就像一个魅力:

  "sort": {
    "warehouses.stock_level": {
      "order": "desc",
      "mode": "sum",
      "nested": {
        "path": "warehouses"
        "filter": {
           "terms": {
             "warehouses.id": [2001, 2003]
           }
        }
      }
    }
  }

但我也找不到访问此排序值的方法:(

任何想法我怎样才能做到这一点?谢谢。

4

1 回答 1

1

我最近有同样的问题。事实证明,在重构期间更改发生在 6.4 左右_source,虽然强烈建议不要访问,但看起来人们仍在使用/想要使用它。

这是利用include_in_root参数的解决方法。

  1. 调整映射
PUT product
{
  "mappings": {
    "properties": {
      "warehouses": {
        "type": "nested",
        "include_in_root": true,     <--
        "properties": {
          "stock_level": {
            "type": "integer"
          }
        }
      }
    }
  }
}
  1. 删除并重新索引
  2. 在访问展平值时,在 for 循环中重建各个仓库项目:
GET product/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "script": {
            "script": {
              "source": """
                  int total = 0;
                  
                  def ids = doc['warehouses.id'];
                  def levels = doc['warehouses.stock_level'];
                  
                  for (def i = 0; i <  ids.length; i++) {
                    def warehouse = ['id':ids[i], 'stock_level':levels[i]];
                    
                    if (params.warehouse_ids == null || params.warehouse_ids.contains(warehouse.id)) {
                      total += warehouse.stock_level;
                    }
                  }
                  
                  boolean gte = true;
                  boolean lte = true;
                  if (params.gte != null) {
                    gte = (total >= params.gte);
                  }
                  if (params.lte != null) {
                    lte = (total <= params.lte);
                  }
                  return (gte && lte);
              """,
              "lang": "painless",
              "params": {
                  "gte": 4
              }
            }
          }
        }
      ]
    }
  }
}

请注意,此方法假定所有仓库都包含非空 id 和库存级别。

于 2020-10-07T12:27:14.647 回答