Elasticsearch:根据类型对不同字段进行排序

时间:2016-04-19 19:39:01

标签: elasticsearch

我的索引中有两种类型(EventCity),我试图按日期对它们进行排序。但是,每个类型的日期字段名称不同: 对于Event,值位于updated_at字段中,而对于City,日期位于update_at字段中city_events嵌套的其中一个嵌套对象中对象数组(注意按region_id过滤)。

我已经尝试像这样指定排序数组中的每个字段:

  "sort": [
    {
      "city_events.updated_at": {
        "order": "desc",
        "nested_path": "city_events",
        "nested_filter": {
          "term": {
            "city_events.region_id": 1
          }
        }
      }
    },
    {
      "updated_at": "desc"
    }
  ]

但不幸的是,这并没有将两种类型混合在一起。相反,它首先按其嵌套的Cities字段对所有city_events.updated_at进行排序,然后将所有Events添加到其updated_at字段排序的底部。如何将两者混合在一起?

作为替代解决方案,我尝试仅使用嵌套的city_events.updated_at字段进行排序并指定"missing": "updated_at",但是尽管这两个字段的格式相同,但仍会出现"number_format_exception"错误:

{
  "error": {
    "root_cause": [
      {
        "type": "number_format_exception",
        "reason": "For input string: \"updated_at\""
      }
    ],
    "type": "search_phase_execution_exception",
    "reason": "all shards failed",
    "phase": "query_fetch",
    "grouped": true,
    "failed_shards": [
      {
        "shard": 0,
        "index": "events_1461095196252",
        "node": "sYQstSw_SN62ojmXgGjPlg",
        "reason": {
          "type": "number_format_exception",
          "reason": "For input string: \"updated_at\""
        }
      }
    ]
  },
  "status": 400
}

更新1 :根据下面的the answer by Andrei Stefan,我尝试开发一个groovy脚本,为每个city_events文档循环City选择一个使用匹配的region_id,然后返回city_event updated_at值进行评分,但在访问脚本中的嵌套字段时遇到问题:https://stackoverflow.com/questions/36781476/elasticsearch-access-fields-inside-array-of-nested-objects-in-a-groovy-script

2 个答案:

答案 0 :(得分:4)

尝试基于script的排序,您需要nested字段才能在脚本中访问include_in_parent: true

    "city_events": {
      "type": "nested",
      "include_in_parent": true, 
      "properties": {
        "updated_at": {
          "type": "date"
        }
      }
    }

排序部分:

  "sort": {
    "_script": {
      "type": "number",
      "script": {
        "inline": "if (doc['_type'].value=='Event') return doc['updated_at'].date.getMillis(); else if (doc['_type'].value=='City') return doc['city_events.updated_at'].date.getMillis()",
        "lang": "groovy"
      },
      "order": "desc"
    }
  }

稍后编辑

即使我将city_events.region_id==1条件添加到Groovy脚本中,也不会感觉到Elasticsearch,这将是纯粹的Groovy编程,而不是Elasticsearch的强大功能。

我尝试过其他方法(全部在ES 2.3.1中):

  • copy_to从常规updated_at字段到nested内的Event字段,以便对所有类型执行常规nested排序。这没有用。
  • 即使copy_to有效,Elasticsearch也不会与来自{"term": {"city_events.region_id": 1}的{​​{1}} region_id匹配Event {1}}部分属于sort类型,对于这些值,我们会使用Event而不是实际日期(这些值来自我执行的测试)。
  • 同时使用-9223372036854776000中的nested字段和索引时间,将Event放在此嵌套字段中。这与上述尝试#2的原因相同:updated_at中必须有region_id,以便来自Event部分的nested过滤器将申请两种类型。

我建议,作为一种正确的处理方法,就是重新思考一下数据结构,以便排序部分(至少)遵循Elasticsearch的做法的东西。您的类型称为sortCity,而在Event内您有一个(嵌套)City列表。您是否可以在city_events中加入Event并复制活动'每个城市的详细信息?这不一定是标准化的RDB数据结构。相反,ES对非标准化数据更满意。

为了完整起见,我不推荐

City

请注意,我还没有在上面的Groovy脚本中完成所有正确的检查(例如,检查文档中是否存在实际的嵌套对象)。

答案 1 :(得分:1)

应优化Elasticsearch数据以供阅读。最好的解决方案是为存储相关排序值的两种类型添加公共字段。

关于城市中的多个嵌套对象:我仍然在城市级别存储最相关(最近)的值。