Elasticsearch教程 — Search APIs

搜索 API 用于搜索和聚合存储在 Elasticsearch 索引和数据流中的数据。时ES的核心语法之一。

核心搜索

# 搜索
# <target>(可选,字符串)要搜索的数据流、索引和别名的逗号分隔列表。支持通配符(*)。要搜索所有数据流和索引,请省略此参数或使用*或_all。
# 查询参数、查询正文参数很多,参考文档
# https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html
GET /<target>/_search
GET /_search
POST /<target>/_search
POST /_search

# 查询参数,URL的参数部分(重要的部分)
analyzer (可选,字符串)用于查询字符串的分析器。
default_operator (可选,字符串)查询字符串查询的默认运算符:AND 或 OR。默认为OR。
q (可选,字符串)以 Lucene 查询字符串语法进行查询。
search_type 搜索类型。分布式搜索操作需要分散到所有相关的分片,然后收集所有的结果。当使用分散/集合类型执行时,有几种方法可以做到这一点,特别是使用搜索引擎。
sort (可选,字符串)以逗号分隔的 <field>:<direction> 对列表。


# 查询正文,body部分(重要的部分)
fields、docvalue_fields (可选,字符串和对象数组)返回的字段,在响应的属性中返回与这些模式匹配的字段名称的值。
from (可选,整数)起始文档偏移量。默认为0。可用于分页。
size 可选,整数)要返回的结果数。默认为10。可用于分页。
explain (可选,布尔值)如果true,返回有关分数计算的详细信息作为命中的一部分。默认为false。
indices_boost 搜索多个索引时,可以提升某个或多个索引的权重。
min_score (可选,浮动)_score匹配文档的最小值。_score搜索结果中不包括具有较低值的文档。
query (可选,查询对象)使用Query DSL定义搜索定义。非常关键。
runtime_mappings 运行时字段,在运行搜索时创建的字段。
_source (可选)指示为匹配文档返回哪些源字段。
stats (可选,字符串数组)为其关联的搜索维护一个统计聚合。
timeout 超时,默认无超时。
version (可选,布尔值)如果true,则返回文档版本作为命中的一部分。
# 单个请求执行多个搜索
# <target>(可选,字符串)要搜索的数据流、索引和别名的逗号分隔列表。
# 查询的参数分两部分<header>与<body>两部分,参数同_search一样。
GET /<target>/_msearch

# 例子
GET my-index-000001/_msearch
{ }
{"query" : {"match" : { "message": "this is a test"}}} # 第一个查询
{"index": "my-index-000002"} # 第二个要查询的索引
{"query" : {"match_all" : {}}} # 第二个查询
# 异步搜索
POST /索引/_async_search?size=0
{
  "sort": [
    { "date": { "order": "asc" } }
  ],
  "aggs": {
    "sale_date": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1d"
      }
    }
  }
}
# 搜索时间点(PIT、Point in time API)(这个api的keep_alive参数点在7.x版本中已经去除了)

# 滚动API(Scroll API)  就像使用快照一样,对其更改或后续添加数据不会影响原数据。
# 滚动不是用于实时用户请求,而是用于处理大量数据(甚至是全部数据,比如更适用于后台批处理任务)。
# 如果请求指定了聚合(aggregation),仅仅初始搜索响应才会包含聚合结果。
# 在url中设置 search_type=scan 可以关闭打分或者排序,让滚动更加高效。
GET /_search/scroll
POST /_search/scroll

# 创建Scroll示例,这里scroll=1m表示请求的结果"保持多长时间"
GET /<index>/_search?scroll=1m
{
  "size": 10, # 分片,定义每次回传几条数据
  "query": {
    "match": {
      "message": "foo"
    }
  }
}

# 在返回的结果中除了原有信息外,还包括一个_scroll_id参数。
{
  "_scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ==",  # 用以下次查询的参数
  "took" : 1,
  "timed_out" : false,
  ****
}


# 第一次或之后可以使用scroll_id来操作第一次返回的_scroll_id结果。
# 如果第二次请求再次带了scroll参数,此值会覆盖由原始搜索API请求的scroll参数设置的持续时间。
# 如果第二次请求不带上scroll参数,那么_scroll_id就会失效。
# 注意:因为有size参数的存在,每次返回size条数据,下次又依次返回下一页的size条数据,直到返回的hits中为空说明将数据全部返回了。
GET /_search/scroll
{
  "scroll" : "1m",
  "scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ==" # 上次请求返回的_scroll_id
}

# Scroll_id是有存在时间限制的,可以通过以下API查看
GET /_nodes/stats/indices/search

# 也可以使用命令清除Scroll_id,也可以批量清除或清除所有
DELETE /_search/scroll
{
  "scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ=="
}
# Suggesters API(建议) 即在用户输入搜索的过程中,进行自动补全或者纠错。
# Suggesters基本的运作原理是将输入的文本分解为token(词元,分析器分析后的单词),然后在索引的字典里查找相似的term并返回。
# 根据使用场景的不同,Elasticsearch里设计了4种类别的Suggester
# Term Suggester(纠错补全,输入错误的情况下补全正确的单词)
# Phrase Suggester(自动补全短语,输入一个单词补全整个短语)
# Completion Suggester(完成补全单词,输出如前半部分,补全整个单词)
# Context Suggester(上下文补全) 

POST /<index>/_search
{
  "query" : { # 查询参数
    "match": {
      "message": "tring out Elasticsearch"
    }
  },
  "suggest" : { # 建议参数
    "my-suggestion" : { # 自定义建议名称
      "text" : "tring out Elasticsearrrrch", # 被建议的字符串,注意这里写错了单词
      "term" : {  # Suggester的类型
        "suggest_mode": "popular", # missing、popular、always
        "field" : "message" # 字段名称
      }
    }
  }
}

# 在返回的信息中
{
    "took": 26,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 0,
        "max_score": 0,
        "hits": []
    },
    "suggest": {
        "my-suggestion": [
            {
                "text": "elasticsearaach",
                "offset": 0,
                "length": 15,
                "options": [ # 这里是返回的一些建议选项,如果为空就表示没建议,不为空就表示有建议
                    {
                        "text": "elasticsearch",  # 建议的正确单词
                        "score": 0.84615386,
                        "freq": 3
                    }
                ]
            }
        ]
    }
}

搜索测试

# explain API 能够解释Document的Score是怎么得来的,具体每一部分的得分都可以详细地打印出来。
# <index> (必需,字符串)索引名称。
# <id> (必需,整数)定义文档ID。
# 返回的信息中的description字段介绍了公式算法,以及各种值的来源及描述。
GET  /<index>/_explain/<id>
POST /<index>/_explain/<id>
# Profile API 帮用户进行性能分析,会提供有关搜索请求中各个组件执行的详细信息。输出非常详细,特别是对于跨多个分片的复杂请求执行。
GET /<index>/_search
{
  "profile": true, # 开启性能分析,注意开启后非常耗费性能
  "query" : {
    "match" : { "message" : "GET /search" }
  }
}

# 在返回的字段中会多返回一个profile字段
{
  "profile" : {
    "shards" : [ # 涉及一个或者多个碎片,每个分片都列出
      {
        "id" : "[Wh0K0xY0Q-apozD1V2fvNA][companies][0]", # 报告惟一的ID标识 [nodeID][indexName][shardID]
        "searches" : [
          {
            "query" : [ # 显示查询的执行的详细分析内容
              {
                "type" : "TermQuery", # type字段显示Lucene类名
                "description" : "search:公司", # description字段显示了查询的Lucene解释文本
                "time_in_nanos" : 6331730, # time_in_nanos字段显示整个查询的花费(纳秒)
                "breakdown" : {...} # 细分组件列出了底层Lucene执行的详细时间统计
              }
            ],
            "rewrite_time" : 5369, # 表示累计重写时间的时间
            "collector" : [ # 关于运行搜索的Lucene收集器的分析
              {
                "name" : "SimpleTopScoreDocCollector",
                "reason" : "search_top_hits", # 尝试给出收集器类名的简单英文描述
                "time_in_nanos" : 4410144
              }
            ]
          }
        ],
        "aggregations" : [ ] # 聚合分析的详细信息,不存在聚合就为空
      }
    ]
  }
}
# Field Capabilities API 允许您在多个索引中检索字段的功能。
GET  /_field_caps?fields=<fields>
POST /_field_caps?fields=<fields>
GET  /<target>/_field_caps?fields=<fields>
POST /<target>/_field_caps?fields=<fields>
# Ranking evaluation API 排名评估 API 允许您评估一组典型搜索查询的排名搜索结果的质量。
# 


# 返回将针对其执行搜索请求的索引和分片。

GET /<target>/_search_shards

{
  "nodes" : {
    "Wh0K0xY0Q-apozD1V2fvNA" : {...},
  "indices" : {
    "companies" : { }
  },
  "shards" : [
    [
      {
        "state" : "STARTED",  # 分配状态
        "primary" : true,
        "node" : "Wh0K0xY0Q-apozD1V2fvNA", # 节点
        "relocating_node" : null,
        "shard" : 0, # 分片id
        "index" : "companies", # 索引
        "allocation_id" : {
          "id" : "yr_FrKqWQhSMyNs2jtOLYw"
        }
      }
    ]
  ]
}
# Validates API(验证API) 验证一个潜在的昂贵的查询而不执行它。
# <target>(可选,字符串)要搜索的数据流、索引和别名
# query(可选,查询对象)使用Query DSL定义搜索定义
GET /<target>/_validate/<query>

GET /<index>/_validate/query
{
  "query" : {
    "bool" : {
      "must" : {
        "query_string" : {
          "query" : "*:*"
        }
      },
      "filter" : {
        "term" : { "user.id" : "kimchy" }
      }
    }
  }
}
# 如果查询是无效的,valid将是false。

搜索模板

# 创建或更新存储的脚本或 搜索模板。
# <script-id>(必需,字符串)存储脚本或搜索模板的标识符。在集群内必须是唯一的。
# <context>(可选,字符串)脚本或搜索模板应在其中运行的上下文。
PUT  _scripts/<script-id>
POST _scripts/<script-id>
PUT  _scripts/<script-id>/<context>
POST _scripts/<script-id>/<context>

# 删除储存脚本
DELETE _scripts/<script-id>

# 获取储存脚本或搜索模板信息
GET _scripts/<script-id>

# 使用示例,创建搜索模板
POST _scripts/my_search_template
{
    "script": {
        "lang": "mustache", # (必需,字符串) 脚本语言。对于搜索模板,请使用 mustache.
        "params": {}, # (可选,对象)脚本或搜索模板的参数。
        "source": { # (必需,字符串或对象)对于脚本,包含脚本的字符串。
            "query": {
                "match": {
                    "msg": "{{query_string}}"
                }
            }
        }
    }
}

# Search Template API(搜索模板) 使用搜索模板运行搜索。
# 搜索模板可让您在不修改应用程序代码的情况下更改搜索,也可以在不向用户公开Elasticsearch查询语法的情况下运行搜索。
# 使得搜索请求参数化,达到开发人员与搜索工程师解耦的效果。
GET  <target>/_search/template
GET  _search/template
POST <target>/_search/template
POST _search/template

# 参数source(必需*,对象)内联搜索模板。支持与搜索API的请求正文相同的参数。
GET <index>/_search/template
{
  "id": "my-search-template", # 与source参数两个需有一个是必须。搜索模板的 ID。
  "params": { #(可选,对象)用于替换模板中的 Mustache 变量的键值对。
    "query_string": "hello world",
    "from": 0,
    "size": 10
  }
}
# Render search template API(渲染搜索模板) 主要用来验证一个搜索模板与传入的数据。
# <template-id>(必需*,字符串)要呈现的搜索模板的 ID。如果没有source指定,则此或id请求正文参数是必需的。
# body参数与搜索模板一致。
GET _render/template
GET _render/template/<template-id>
POST _render/template
POST _render/template/<template-id>

地理空间搜索

# 搜索地理空间值
# <target>(必需,字符串)要搜索的数据流、索引或别名的逗号分隔列表
# <field>(必需,字符串)包含要返回的地理空间值的字段。必须是一个geo_point或geo_shape字段
# <zoom>(必需,整数)要搜索的矢量切片的缩放级别。接受0- 29
# <x> <y>(必需,整数)要搜索的矢量切片的X坐标,Y坐标
# 
GET <target>/_mvt/<field>/<zoom>/<x>/<y>
POST <target>/_mvt/<field>/<zoom>/<x>/<y>

案例:ES提供的几种分页方法

具体的参考官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.16/paginate-search-results.html
注意:ES是分布式系统,查询数据时,会分别从每个分片查询后汇总到一起再返回。分页时size=10&from=990虽然只返回10条,但是ES会从每个分片中查询1000条返回到一起,聚合后再取第990-1000这10条数据返回。所以,深度分页(from很大时)通常在分布式系统中分页的效率会很低。

From + Size 查询

这个比较常规了
缺点:越往后的分页执行的效率越低,第一次查询与第二次查询的可能导致重复。
优点:支持随机翻页

Scroll 查询

参考上面提到的Scroll分页。不过ES官方文档中不推荐采取这种方式进行深度分页。官方建议深度分页采用Search After方式。

Search After 查询

search_after查询本质:使用前一页中的一组排序值来检索匹配的下一页。在第一次请求时,必须加上sort字段,返回第一页列表的最后值的sort字段,下一次请求时携带search_after参数,此参数使用上一次请求携带的sort值。
search_after缺点:是不能够随机跳转分页,只能是一页一页的向后翻,并且需要至少指定一个唯一不重复字段来排序。
search_after优点:适合深度分页,

# 第一页请求示例
GET twitter/_search
{
  "size": 2,
  "query": {
    "match": {
      "city": "北京"
    }
  },
  "sort": [ # 必须要携带这个参数,因为携带这个参数才会在结果中返回这个参数
    {"DOB":{"order": "asc"}},
    {"user.keyword": {"order": "asc"}}
  ]
}

# 第一页请求结果
{
  "took" : 29,
  "timed_out" : false,
  "_shards" : {
    "total" : 1
  },
  "hits" : {
    "hits" : [
      {
        "_index" : "twitter",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : null,
        "_source" : {

        },
        "sort" : [  # 这里返回的是最后一条数据的sort参数
          347155200000,
          "东城区-老刘"
        ]
      }
    ]
  }
}
# 下一页请求示例
GET twitter/_search
{
  "size": 2,
  "from": 0, # 当我们使用search_after时,from值必须设置为0
  "query": {
    "match": {
      "city": "北京"
    }
  },
  "search_after": [ # 这里使用上一页请求的最后数据
    347155200000,
    "东城区-老刘"
  ],
  "sort": [ # 必须要携带这个参数,因为携带这个参数才会在结果中返回这个参数
    {"DOB":{"order": "asc"}},
    {"user.keyword": {"order": "asc"}}
  ]
}

相关文章

此处评论已关闭