【官方文档翻译】映射 - 在一个搜索请求里定义运行时字段 - Elasticsearch

88 阅读3分钟

在一个搜索请求里定义运行时字段(Define runtime fields in a search request)

你可以在一个搜索请求里指定一个 runtime_mappings 部分以创建一个只作为这次请求的一部分存在的运行时字段。你指定的脚本,作为 runtime_mappings 段的一部分的,和你如果想要添加一个运行时字段到映射里的一样。
定义一个搜索请求里的运行时字段和定义一个索引映射里的运行时字段使用同样的格式。只需要将字段定义从搜索请求里的 runtime_mappings 拷贝到索引映射里的 runtime 段。
下面的搜索请求添加了一个 day_of_week 字段到 runtime_mappings 段。字段的值将被动态的计算,并且只存在于这次请求的上下文。

GET my-index-000001/_search
{
  "runtime_mappings": {
    "day_of_week": {
      "type": "keyword",
      "script": {
        "source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ROOT))"
      }
    }
  },
  "aggs": {
    "day_of_week": {
      "terms": {
        "field": "day_of_week"
      }
    }
  }
}

创建使用了其它运行时字段的运行时字段

你甚至可以在一个从其它运行时字段返回值的搜索请求里定义运行时字段。例如,假如你批量索引一些传感器数据:

POST my-index-000001/_bulk?refresh=true
{"index":{}}
{"@timestamp":1516729294000,"model_number":"QVKC92Q","measures":{"voltage":"5.2","start": "300","end":"8675309"}}
{"index":{}}
{"@timestamp":1516642894000,"model_number":"QVKC92Q","measures":{"voltage":"5.8","start": "300","end":"8675309"}}
{"index":{}}
{"@timestamp":1516556494000,"model_number":"QVKC92Q","measures":{"voltage":"5.1","start": "300","end":"8675309"}}
{"index":{}}
{"@timestamp":1516470094000,"model_number":"QVKC92Q","measures":{"voltage":"5.6","start": "300","end":"8675309"}}
{"index":{}}
{"@timestamp":1516383694000,"model_number":"HG537PU","measures":{"voltage":"4.2","start": "400","end":"8625309"}}
{"index":{}}
{"@timestamp":1516297294000,"model_number":"HG537PU","measures":{"voltage":"4.0","start": "400","end":"8625309"}}

索引后你意识到你的数字型的数据被映射为了 text 类型。你想要在 measures.startmeasures.end 上聚合,但是聚合失败了因为你不能在一个 text 类型的字段上做聚合。运行时字段来挽救!你可以添加一个和你的索引字段同名的运行时字段并改变它的数据类型:

PUT my-index-000001/_mapping
{
  "runtime": {
    "measures.start": {
      "type": "long"
    },
    "measures.end": {
      "type": "long"
    }
  }
}

运行时字段比在索引映射里定义的同名字段更有优先级。这个灵活性允许你影射现有的字段并且计算一个不同的值而不需要改变这个字段本身。如果你在索引映射里犯了一个错误,你可以在搜索请求期间使用运行时字段来计算在映射里覆盖值后的值。
现在,你可以非常容易地在 measures.startmeasures.end 上运行一个平均聚合:

GET my-index-000001/_search
{
  "aggs": {
    "avg_start": {
      "avg": {
        "field": "measures.start"
      }
    },
    "avg_end": {
      "avg": {
        "field": "measures.end"
      }
    }
  }
}

响应包含了聚合后的数据而不需要改变底层数据的值:

{
  "aggregations" : {
    "avg_start" : {
      "value" : 333.3333333333333
    },
    "avg_end" : {
      "value" : 8658642.333333334
    }
  }
}

更进一步地,你可以定义一个运行时字段作为搜索请求的一部分来计算值,然后在同一个查询里在这个字段上运行一个 统计聚合
这个 duration 运行时字段在索引映射里不存在,但是我们仍然可以在那个字段上进行搜索和聚合。下面的查询返回 duration 字段的值并运行一个统计聚合-从那些聚合后的文档中提取的数字型值上计算统计。

GET my-index-000001/_search
{
  "runtime_mappings": {
    "duration": {
      "type": "long",
      "script": {
        "source": """
          emit(doc['measures.end'].value - doc['measures.start'].value);
          """
      }
    }
  },
  "aggs": {
    "duration_stats": {
      "stats": {
        "field": "duration"
      }
    }
  }
}

虽然 duration 字段只存在于这个搜索请求的上下文,你仍然可以在那个字段上搜索和聚合。这个灵活性简直难以置信的棒,使你能够修复索引映射里的错误并且动态地完成计算,所有这一切包含在一个单个的搜索请求里。

{
  "aggregations" : {
    "duration_stats" : {
      "count" : 6,
      "min" : 8624909.0,
      "max" : 8675009.0,
      "avg" : 8658309.0,
      "sum" : 5.1949854E7
    }
  }
}