【官方文档翻译】映射 - 检索一个运行时字段 - Elasticsearch

110 阅读5分钟

检索一个运行时字段

使用 _search API 上的 fields检索运行时字段的值。运行时字段不会在 _source 里展示,但是 fields API 为所有的字段工作,甚至那些不会作为原始 _source 的一部分发送的字段。

1. 定义一个计算一周第几天的运行时字段

例如,下面的请求添加一个称为 day_of_week 的运行时字段。这个运行时字段包含一个基于 @timestamp 字段的值计算一周第几天的脚本。我们将在请求里包含 "dynamic":"runtime",这样新加到映射里的字段会被当作运行时字段。

PUT my-index-000001/
{
  "mappings": {
    "dynamic": "runtime",
    "runtime": {
      "day_of_week": {
        "type": "keyword",
        "script": {
          "source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ROOT))"
        }
      }
    },
    "properties": {
      "@timestamp": {"type": "date"}
    }
  }
}

2. 摄取一些数据

让我们摄取一些示例数据,这将导致两个被索引的字段:@timestampmessage

POST /my-index-000001/_bulk?refresh
{ "index": {}}
{ "@timestamp": "2020-06-21T15:00:01-05:00", "message" : "211.11.9.0 - - [2020-06-21T15:00:01-05:00] "GET /english/index.html HTTP/1.0" 304 0"}
{ "index": {}}
{ "@timestamp": "2020-06-21T15:00:01-05:00", "message" : "211.11.9.0 - - [2020-06-21T15:00:01-05:00] "GET /english/index.html HTTP/1.0" 304 0"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:30:17-05:00", "message" : "40.135.0.0 - - [2020-04-30T14:30:17-05:00] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:30:53-05:00", "message" : "232.0.0.0 - - [2020-04-30T14:30:53-05:00] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:31:12-05:00", "message" : "26.1.0.0 - - [2020-04-30T14:31:12-05:00] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:31:19-05:00", "message" : "247.37.0.0 - - [2020-04-30T14:31:19-05:00] "GET /french/splash_inet.html HTTP/1.0" 200 3781"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:31:27-05:00", "message" : "252.0.0.0 - - [2020-04-30T14:31:27-05:00] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:31:29-05:00", "message" : "247.37.0.0 - - [2020-04-30T14:31:29-05:00] "GET /images/hm_brdl.gif HTTP/1.0" 304 0"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:31:29-05:00", "message" : "247.37.0.0 - - [2020-04-30T14:31:29-05:00] "GET /images/hm_arw.gif HTTP/1.0" 304 0"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:31:32-05:00", "message" : "247.37.0.0 - - [2020-04-30T14:31:32-05:00] "GET /images/nav_bg_top.gif HTTP/1.0" 200 929"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:31:43-05:00", "message" : "247.37.0.0 - - [2020-04-30T14:31:43-05:00] "GET /french/images/nav_venue_off.gif HTTP/1.0" 304 0"}

3. 搜索计算的一周第几天

下面的请求使用搜索 API 检索 day_of_week 字段 - 在最初的请求里作为映射里的一个运行时字段定义的。字段的值在查询时被动态地计算而不需要重新索引文档或索引 day_of_week 字段。 如此的弹性允许你不需要改变任何字段的值就能更改映射。

GET my-index-000001/_search
{
  "fields": [
    "@timestamp",
    "day_of_week"
  ],
  "_source": false
}

前面的请求返回所有匹配文档的 day_of_week 字段。我们可以定义另外被称为 client_ip 的操作 message 字段的运行时字段,这将使查询变得更好:

PUT /my-index-000001/_mapping
{
  "runtime": {
    "client_ip": {
      "type": "ip",
      "script" : {
      "source" : "String m = doc["message"].value; int end = m.indexOf(" "); emit(m.substring(0, end));"
      }
    }
  }
}

运行另一个查询,使用 client_ip 运行时字段搜索一个特定的 IP 地址:

GET my-index-000001/_search
{
  "size": 1,
  "query": {
    "match": {
      "client_ip": "211.11.9.0"
    }
  },
  "fields" : ["*"]
}

这时,响应只包含了两个命中。 在查询时通过使用定义在映射里的运行时脚本计算 day_of_week(Sunday) 的值,并且结果只包含了匹配到 211.11.9.0 IP 地址的文档。

{
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "my-index-000001",
        "_id" : "oWs5KXYB-XyJbifr9mrz",
        "_score" : 1.0,
        "_source" : {
          "@timestamp" : "2020-06-21T15:00:01-05:00",
          "message" : "211.11.9.0 - - [2020-06-21T15:00:01-05:00] "GET /english/index.html HTTP/1.0" 304 0"
        },
        "fields" : {
          "@timestamp" : [
            "2020-06-21T20:00:01.000Z"
          ],
          "client_ip" : [
            "211.11.9.0"
          ],
          "message" : [
            "211.11.9.0 - - [2020-06-21T15:00:01-05:00] "GET /english/index.html HTTP/1.0" 304 0"
          ],
          "day_of_week" : [
            "Sunday"
          ]
        }
      }
    ]
  }
}

4. 从关联索引里检索字段

此功能处于技术预审阶段在未来的版本中可能会改变或移除。Elastic 将提供最好的努力去解决任何的 issue,但是技术预审中的功能不受正式 GA 特性支持 SLA 的约束。

_search API 上的 fields 参数也能被用于检索来自于关联索引的字段,通过一个 lookup 类型的运行时字段。

POST ip_location/_doc?refresh
{
  "ip": "192.168.1.1",
  "country": "Canada",
  "city": "Montreal"
}

PUT logs/_doc/1?refresh
{
  "host": "192.168.1.1",
  "message": "the first message"
}

PUT logs/_doc/2?refresh
{
  "host": "192.168.1.2",
  "message": "the second message"
}

POST logs/_search
{
  "runtime_mappings": {
    "location": {
        "type": "lookup",   // @1
        "target_index": "ip_location",  // @2 
        "input_field": "host",  // @3
        "target_field": "ip",   // @4
        "fetch_fields": ["country", "city"] // @5 
    }
  },
  "fields": [
    "host",
    "message",
    "location"
  ],
  "_source": false
}

@1:在主搜索请求中定义一个类型为 lookup 的运行时字段,使用 term 查询检索来自于目标索引的字段。
@2:lookup 查询要执行的目标索引
@3:主索引中的一个字段,此字段的值作为 lookup 查询项的输入值
@4:lookup 查询要搜索的查找索引中的字段
@5:从查找索引中检索的字段列表。查看搜索请求的 feilds参数。

上面的搜索为返回的每一个搜索命中 ip 地址返回来自于 ip_location 索引中的 country 和 city 。

{
  "took": 3,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 1.0,
    "hits": [
      {
        "_index": "logs",
        "_id": "1",
        "_score": 1.0,
        "fields": {
          "host": [ "192.168.1.1" ],
          "location": [
            {
              "city": [ "Montreal" ],
              "country": [ "Canada" ]
            }
          ],
          "message": [ "the first message" ]
        }
      },
      {
        "_index": "logs",
        "_id": "2",
        "_score": 1.0,
        "fields": {
          "host": [ "192.168.1.2" ],
          "message": [ "the second message" ]
        }
      }
    ]
  }
}

响应的查找字段被分组以保持来自于查找索引中的每一个文档的独立性。每一个输入值的查找查询预期匹配最多一条查找索引中的文档。如果查找查询匹配到了多于一个的文档,那么将选择一个随机的文档。