ElasticSearch检索你的数据(一)

ElasticSearch检索你的数据(一)

检索你的数据

检索查询是针对ElasticSearch上的数据流或者索引数据信息的一个请求。

你可以把查询看做是一个问题,以ElasticSearch理解的方式编写。基于你的数据,你可以使用查询来获取以下问题的答案:

  • 我服务器上的哪些进的响应时间超过 500 毫秒?
  • 上周我网络上的哪些用户运行了 regsvr32.exe?
  • 我网站上的哪些页面包含特定的字词或短语?

一个检索包含一个或者更多合并在一起的查询并发送给ElasticSearch。匹配到的检索文档被返回到hits中,或者检索结果中。

每一个检索也可能包含用于更好的处理其查询的额外信息。例如一个检索可能被限制在一个索引上或者返回特定数量的结果。

运行一个检索

你可以使用search API检索和聚合存在ElasticSearch上的数据或者索引。这个API的query请求体参数接收query DSL编写的查询。

根据以下请求使用match查询检索my-index-00001。这个查询匹配user.id的值为kimchy的文档。

curl -X GET "localhost:9200/my-index-000001/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "user.id": "kimchy"
    }
  }
}
'

这个API响应返回匹配这个查询的前十条文档,

{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.3862942,
    "hits": [
      {
        "_index": "my-index-000001",
        "_type": "_doc",
        "_id": "kxWFcnMByiguvud1Z8vC",
        "_score": 1.3862942,
        "_source": {
          "@timestamp": "2099-11-15T14:12:12",
          "http": {
            "request": {
              "method": "get"
            },
            "response": {
              "bytes": 1070000,
              "status_code": 200
            },
            "version": "1.1"
          },
          "message": "GET /search HTTP/1.1 200 1070000",
          "source": {
            "ip": "127.0.0.1"
          },
          "user": {
            "id": "kimchy"
          }
        }
      }
    ]
  }
}

定义只存在查询中的字段

你可以定义一个只存在于你检索查询部分中运行时字段,而不是索引你的数据然后检索他。你可以在查询请求中指定一个runtime_mapping片段来定义运行时字段,这个运行时字段包含脚本是可选的。

例如根据查询定义一个名字为day_of_week的运行时字段。其中包含了根据@timestamp字段的值去计算星期几的脚本,并且是用emit字段来接收计算值。

这个查询也包含了在day_of_week上的terms aggregation操作:

curl -X GET "localhost:9200/my-index-000001/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "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"
      }
    }
  }
}
'

响应包含了基于day_of_week运行时字段的聚合值。buckets中是一个值为Sundaykey。这个查询根据脚本中定义的运行时字段day_of_week动态计算了星期几,而不是对该字段进行索引。

{
  ...
  ***
  "aggregations" : {
    "day_of_week" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "Sunday",
          "doc_count" : 5
        }
      ]
    }
  }
}	

通用的检索选项

你可以通过以下选项自定义你的检索

Query DSL

Query DSL支持多种检索类型,你可以搭配使用来获取你想要的结果。查询类型包含以下:

  • 布尔查询和其他复合查询,可让您根据多个条件组合查询并匹配结果
  • 用于过滤和查找完全匹配项的术语级查询
  • 全文查询,常用于搜索引擎
  • 地理和空间查询
Aggregations

你可以使用aggregate检索来获取统计和其他分析的结果。Aggregation可以回到你一下问题:

  • 我的服务器的平均响应时间
  • 使用我们网络的前N个IP地址
  • 客户的总交易收入是多少?
检索多个数据流和索引

您可以使用逗号分隔值和类似 grep 的索引模式在同一请求中搜索多个数据流和索引。您甚至可以提升特定索引的搜索结果。请参阅搜索多个数据流和索引。

分页你的结果

默认情况下,搜索仅返回前 10 个匹配的匹配项。要检索更多或更少的文档,请参阅分页搜索结果。

检索选定的字段

搜索响应的 hit.hits 属性包括每次命中的完整文档 _source。要仅检索 _source 或其他字段的子集,请参阅检索所选字段。

排序检索结果

默认情况下,搜索命中按 _score 排序,_score 是衡量每个文档与查询匹配程度的相关性分数。要自定义这些分数的计算,请使用 script_score 查询。要按其他字段值对搜索结果进行排序,请参阅对搜索结果进行排序。

运行异步查询

Elasticsearch 搜索旨在快速在大量数据上运行,通常在几毫秒内返回结果。因此,默认情况下搜索是同步的。搜索请求在返回响应之前等待完整的结果。

但是,对于多个集群的搜索,完整的结果可能需要更长的时间。

为避免长时间等待,您可以改为运行异步或异步搜索。异步搜索可让您现在检索长时间运行的搜索的部分结果,并在以后获得完整的结果。

检索超时

默认情况下,搜索请求不会超时。请求在返回响应之前等待来自每个分片的完整结果。

虽然异步搜索是为长时间运行的搜索而设计的,但您也可以使用 timeout 参数来指定您希望等待每个分片完成的持续时间。每个分片收集指定时间内的记录。如果时间结束时收集没有完成,ElasticSearch将只使用当前时间点命中的记录。检索请求的整体延迟取决于索引的分片数量和并发请求分片的数量。

curl -X GET "localhost:9200/my-index-000001/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "timeout": "2s",
  "query": {
    "match": {
      "user.id": "kimchy"
    }
  }
}
'

为每一个请求设置集群范围内的超时时间,可以使用cluster settings API设置search.default_search_timeout。如果请求没有传递超时时间,则使用全局超时时间。如果全局超时时间在检索请求完成之前过期了,则这个请求将使用任务取消来取消。search.default_search_timeout默认为-1(没有超时时间)

检索取消

你可以使用task management APi来取消检索请求。ElasticSearch也可以在你的客户端都是连接的时候自动取消检索请求。我们推荐你设置你的客户端在请求中止或者超时的时候关闭http连接。

跟踪总记录数

通常,如果不访问所有匹配项,就无法准确计算总命中数,这对于匹配大量文档的查询来说代价很高。track_total_hits参数允许您控制如何跟踪总命中数。通常有一个命中数的下限就足够了,例如“至少有 10000 次命中”,默认设置为 10,000。这意味着请求将准确计算总命中数,最多为 10,000 次命中。如果在某个阈值之后不需要准确的命中数,那么加快搜索速度是一个很好的折衷方案。

当设置为 true 时,搜索响应将始终跟踪准确匹配查询的命中数(例如,当 track_total_hits 设置为 true 时,total.relation 将始终等于eq)。否则在搜索响应的total对象中返回total.relationgte值表示total.value是与查询匹配的总命中数的下限,eq值表示total.value是准确计数。

curl -X GET "localhost:9200/my-index-000001/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "track_total_hits": true,
  "query": {
    "match" : {
      "user.id" : "elkbee"
    }
  }
}
'

返回:

{
  "_shards": ...
  "timed_out": false,
  "took": 100,
  "hits": {
    "max_score": 1.0,
    "total" : {
      "value": 2048,    //总记录数
      "relation": "eq"  //精确统计命中标识
    },
    "hits": ...
  }
}

也可以将 track_total_hits 设置为整数。例如,以下查询将准确跟踪与查询匹配的总命中数最多 100 个文档:

curl -X GET "localhost:9200/my-index-000001/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "track_total_hits": 100,
  "query": {
    "match": {
      "user.id": "elkbee"
    }
  }
}
'

返回:

{
  "_shards": ...
  "timed_out": false,
  "took": 30,
  "hits": {
    "max_score": 1.0,
    "total": {
      "value": 42,         
      "relation": "eq"     
    },
    "hits": ...
  }
}

如果与查询匹配的总命中数大于 track_total_hits 中设置的值,则响应中的总命中数将指示返回值是下限:

{
  "_shards": ...
  "hits": {
    "max_score": 1.0,
    "total": {
      "value": 100,         
      "relation": "gte"     
    },
    "hits": ...
  }
}

如果您根本不需要跟踪总匹配数,您可以通过将此选项设置为 false 来缩短查询时间:

curl -X GET "localhost:9200/my-index-000001/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "track_total_hits": false,
  "query": {
    "match": {
      "user.id": "elkbee"
    }
  }
}
'

返回:

{
  "_shards": ...
  "timed_out": false,
  "took": 10,
  "hits": {             
    "max_score": 1.0,
    "hits": ...
  }
}

快速检查匹配文档

如果只想知道是否有任何文档匹配特定的查询,可以将size设置为0,表示我们对搜索结果不感兴趣。还可以将terminate_after设置为1,表示只要找到第一个匹配的文档(每个分片),就可以终止查询执行。

curl -X GET "localhost:9200/_search?q=user.id:elkbee&size=0&terminate_after=1&pretty"

当大小设置为0时,响应将不包含任何命中。hits.total如果等于0,则说明没有匹配到任何文档。如果大于0,则说明在终止检索之前匹配了对应数量的文档。此外,如果查询提前终止,则在响应中将terminated_early的标志为true

{
  "took": 3,
  "timed_out": false,
  "terminated_early": true,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped" : 0,
    "failed": 0
  },
  "hits": {
    "total" : {
        "value": 1,
        "relation": "eq"
    },
    "max_score": null,
    "hits": []
  }
}

响应中took的时间包含了处理该请求所花费的毫秒数,从节点收到查询开始,一直到所有搜索相关工作完成,并在将上述JSON返回给客户端之前。这意味着它包括在线程池中等待、跨整个集群执行分布式搜索和收集所有结果所花费的时间。

过滤检索结果

你可以使用两种方法过滤检索结果:

  • 使用带有filter子句的布尔查询。检索请求对搜索结果和聚合应用布尔过滤器。
  • 使用检索API的post_filter参数。检索请求只对检索结果应用post_filter,而不应用于aggregation。你可以使用post filter根据结果集计算聚合,进一步缩小结果范围。

Post Filter

当您使用post_filter对检索结果进行过滤的时候,过滤的是聚合之后的结果。该过滤器不会对聚合结果产生影响。

例如,您正在销售具有以下属性的衬衫:

curl -X PUT "localhost:9200/shirts?pretty" -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "properties": {
      "brand": { "type": "keyword"},
      "color": { "type": "keyword"},
      "model": { "type": "keyword"}
    }
  }
}
'
curl -X PUT "localhost:9200/shirts/_doc/1?refresh&pretty" -H 'Content-Type: application/json' -d'
{
  "brand": "gucci",
  "color": "red",
  "model": "slim"
}
'

假设用户指定了两个过滤器:

color:red and brand:gucci。你只想在检索结果中展示由Gucci制造的红色衬衫。通常你会用bool查询来做到这一点:

curl -X GET "localhost:9200/shirts/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "filter": [
        { "term": { "color": "red"   }},
        { "term": { "brand": "gucci" }}
      ]
    }
  }
}
'

但是,您还希望使用分面导航来显示用户可以单击的其他选项列表。也许您有一个模型字段,允许用户将他们的搜索结果限制为红色Gucci t恤或正装衬衫。

这可以通过术语聚合来完成:

curl -X GET "localhost:9200/shirts/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "filter": [
        { "term": { "color": "red"   }},
        { "term": { "brand": "gucci" }}
      ]
    }
  },
  "aggs": {
    "models": {
      "terms": { "field": "model" } 
    }
  }
}
'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值