Elasticsearch笔记

Elasticsearch(ES)笔记与总结

ES是基于Lucene的分布式全文搜索引擎,但是它的目的是使全文检索变得简单, 通过隐藏 Lucene 的复杂性,取而代之的提供一套简单一致的 RESTful API。

安装教程可以直接在网上搜索,安装完成后可以访问: http://localhost:9200 进行查看是否安装成功。

ES的API访问格式为: curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>' < >为标记的部件说明如下:

  • VERB:适当的 HTTP 方法 或 谓词 : GET、 POST、 PUT、 HEAD 或者 DELETE。
  • PROTOCOL:http 或者 https(如果你在 Elasticsearch 前面有一个 https 代理)
  • HOST:Elasticsearch 集群中任意节点的主机名,或者用 localhost 代表本地机器上的节点。
  • PORT:运行 Elasticsearch HTTP 服务的端口号,默认是 9200 。
  • PATH:API 的终端路径(例如 count 将返回集群中文档数量)。Path 可能包含多个组件,例如:cluster/stats 和 _nodes/stats/jvm 。
  • QUERY_STRING:任意可选的查询字符串参数 (例如 ?pretty 将格式化地输出 JSON 返回值,使其更容易阅读)
  • BODY:任意可选的查询字符串参数 (例如 ?pretty 将格式化地输出 JSON 返回值,使其更容易阅读) ES尽可能地屏蔽了分布式系统的复杂性。这里列举了一些在后台自动执行的操作:
  • 分配文档到不同的容器 或 分片 中,文档可以储存在一个或多个节点中
  • 按集群节点来均衡分配这些分片,从而对索引和搜索过程进行负载均衡
  • 复制每个分片以支持数据冗余,从而防止硬件故障导致的数据丢失
  • 将集群中任一节点的请求路由到存有相关数据的节点
  • 集群扩容时无缝整合新节点,重新分配分片以便从离群节点恢复

原理与理论

ES的集群监控信息中包含了许多的统计数据,其中最为重要的一项就是 集群健康 , 它在 status 字段中展示为 green 、 yellow 或者 red 。GET /_cluster/health 可查看状态。说明如下:

  • green:所有的主分片和副本分片都正常运行。
  • yellow:所有的主分片都正常运行,但不是所有的副本分片都正常运行。
  • red:有主分片没能正常运行。

ES使用的是乐观并发控制所以修改突是不可能发生的,并且不会阻塞正在尝试的操作。如果源数据在读写当中被修改,更新将会失败会重试一定次数、使用新的数据、或者将相关情况报告给用户。

新建、索引和删除单个文档

  1. 客户端向 节点 发送新建、索引或者删除请求。
  2. 节点使用文档的 _id 确定文档属于分片 0 。请求会被转发到 其他节点,选择有分片 0 的主分片节点。
  3. 被选择的节点在主分片上面执行请求。如果成功了,它将请求并行转发到 其他节点的副本分片上。一旦所有的副本分片都报告成功, 则将向协调节点原路报告成功,协调节点向客户端报告成功。

取回单个文档

  1. 客户端向 Node 1 发送获取请求。
  2. 节点使用文档的 _id 来确定文档属于分片 0 。分片 0 的副本分片存在于所有的三个节点上。 在这种情况下,它将请求转发到 Node 2 。
  3. Node 2 将文档返回给 Node 1 ,然后将文档返回给客户端。

局部更新文档

  1. 客户端向 Node 1 发送更新请求。
  2. 它将请求转发到主分片所在的 Node 3 。
  3. Node 3 从主分片检索文档,修改 _source 字段中的 JSON ,并且尝试重新索引主分片的文档。 如果文档已经被另一个进程修改,它会重试步骤 3 ,超过 retry_on_conflict 次后放弃。
  4. 如果 Node 3 成功地更新文档,它将新版本的文档并行转发到 Node 1 和 Node 2 上的副本分片,重新建立索引。 一旦所有副本分片都返回成功, Node 3 向协调节点也返回成功,协调节点向客户端返回成功。

使用 mget 取回多个文档

  1. 客户端向 Node 1 发送 mget 请求。
  2. Node 1 为每个分片构建多文档获取请求,然后并行转发这些请求到托管在每个所需的主分片或者副本分片的节点上。一旦收到所有答复, Node 1 构建响应并将其返回给客户端。

使用 bulk 修改多个文档

  1. 客户端向 Node 1 发送 bulk 请求。
  2. Node 1 为每个节点创建一个批量请求,并将这些请求并行转发到每个包含主分片的节点主机。
  3. 主分片一个接一个按顺序执行每个操作。当每个操作成功时,主分片并行转发新文档(或删除)到副本分片,然后执行下一个操作。 一旦所有的副本分片报告所有操作成功,该节点将向协调节点报告成功,协调节点将这些响应收集整理并返回给客户端。

文档存储

倒排索引需要知道集合中的 所有 文档,这是需要认识到的关键问题。

早期的全文检索会为整个文档集合建立一个很大的倒排索引并将其写入到磁盘。 一旦新的索引就绪,旧的就会被其替换,这样最近的变化便可以被检索到。

倒排索引被写入磁盘后是 不可改变 的:它永远不会修改。 不变性有重要的价值:

  • 不需要锁。如果你从来不更新索引,你就不需要担心多进程同时修改数据的问题。
  • 一旦索引被读入内核的文件系统缓存,便会留在哪里,由于其不变性。只要文件系统缓存中还有足够的空间,那么大部分读请求会直接请求内存,而不会命中磁盘。这提供了很大的性能提升。
  • 其它缓存(像filter缓存),在索引的生命周期内始终有效。它们不需要在每次数据改变时被重建,因为数据不会变化。
  • 写入单个大的倒排索引允许数据被压缩,减少磁盘 I/O 和 需要被缓存到内存的索引的使用量。

ES使用更多的索引解决文档在保留不变性的前提下实现倒排索引的更新。通过增加新的补充索引来反映新近的修改,而不是直接重写整个倒排索引。每一个倒排索引都会被轮流查询到—从最早的开始—查询完后再对结果进行合并。

文档的存储过程

一个 Lucene 索引包含一个提交点和三个段:

  1. 新文档被收集到内存索引缓存

  2. 不时地, 缓存被 提交 :

    • 一个新的段—一个追加的倒排索引—被写入磁盘。
    • 一个新的包含新段名字的 提交点 被写入磁盘。
    • 磁盘进行 同步 — 所有在文件系统缓存中等待的写入都刷新到磁盘,以确保它们被写入物理文件。
  3. 新的段被开启,让它包含的文档可见以被搜索。

  4. 内存缓存被清空,等待接收新的文档。

一个在内存缓存中包含新文档的 Lucene 索引。

在一次提交后,一个新的段被添加到提交点而且缓存被清空。

段是不可改变的,所以既不能从把文档从旧的段中移除,也不能修改旧的段来进行反映文档的更新。 取而代之的是,每个提交点会包含一个 .del 文件,文件中会列出这些被删除文档的段信息。

当一个文档被 “删除” 时,它实际上只是在 .del 文件中被 标记 删除。一个被标记删除的文档仍然可以被查询匹配到, 但它会在最终结果被返回前从结果集中移除。

文档更新也是类似的操作方式:当一个文档被更新时,旧版本文档被标记删除,文档的新版本被索引到一个新的段中。 可能两个版本的文档都会被一个查询匹配到,但被删除的那个旧版本文档在结果集返回前就已经被移除。

在ES和磁盘之间是文件系统缓存。有一个内存索引缓冲区,文档会先被写入到一个新的段中。但是这里新段会被先写入到文件系统缓存—这一步代价会比较低,稍后再被刷新到磁盘—这一步代价比较高。不过只要文件已经在缓存中, 就可以像其它文件一样被打开和读取了。在内存缓冲区中包含了新文档的 Lucene 索引。缓冲区的内容会被写入一个可被搜索的段中,但还没有进行提交。可以通过POST /_refreshPOST /<INDEX>/_refresh来刷新缓冲区。

如果没有用 fsync 把数据从文件系统缓存刷(flush)到硬盘,我们不能保证数据在断电甚至是程序正常退出之后依然存在。为了保证 ES 的可靠性,需要确保数据变化被持久化到磁盘。ES增加了一个 translog ,或者叫事务日志,在每一次对 Elasticsearch 进行操作时均进行了日志记录。通过 translog ,整个流程看起来是下面这样:

  1. 一个文档被索引之后,就会被添加到内存缓冲区,并且 追加到了 translog。新的文档被添加到内存缓冲区并且被追加到了事务日志。

  2. 刷新(refresh)使分片,分片每秒被刷新(refresh)一次。刷新(refresh)完成后, 缓存被清空但是事务日志不会。

    • 这些在内存缓冲区的文档被写入到一个新的段中,且没有进行 fsync 操作。
    • 这个段被打开,使其可被搜索。
    • 内存缓冲区被清空。
  3. 这个进程继续工作,更多的文档被添加到内存缓冲区和追加到事务日志。事务日志不断积累文档。

  4. 每隔一段时间—例如 translog 变得越来越大—索引被刷新(flush);一个新的 translog 被创建,并且一个全量提交被执行。

    • 所有在内存缓冲区的文档都被写入一个新的段。
    • 缓冲区被清空。
    • 一个提交点被写入硬盘。
    • 文件系统缓存通过 fsync 被刷新(flush)。
    • 老的 translog 被删除。

translog 提供所有还没有被刷到磁盘的操作的一个持久化纪录。当 Elasticsearch 启动的时候, 它会从磁盘中使用最后一个提交点去恢复已知的段,并且会重放 translog 中所有在最后一次提交后发生的变更操作。

translog 也被用来提供实时 CRUD 。当你试着通过ID查询、更新、删除一个文档,它会在尝试从相应的段中检索之前, 首先检查 translog 任何最近的变更。这意味着它总是能够实时地获取到文档的最新版本。

执行一个提交并且截断 translog 的行为在 Elasticsearch 被称作一次 flush 。 分片每30分钟被自动刷新(flush),或者在 translog 太大的时候也会刷新。手动刷新格式为:POST /<INDEX>/_flush

由于自动刷新流程每秒会创建一个新的段 ,这样会导致短时间内的段数量暴增。而段数目太多会带来较大的麻烦。 每一个段都会消耗文件句柄、内存和cpu运行周期。更重要的是,每个搜索请求都必须轮流检查每个段;所以段越多,搜索也就越慢。

ES通过在后台进行段合并来解决这个问题。段合并的时候会将那些旧的已删除文档从文件系统中清除。被删除的文档(或被更新文档的旧版本)不会被拷贝到新的大段中。过程如下:

  1. 当索引的时候,刷新(refresh)操作会创建新的段并将段打开以供搜索使用。

  2. 合并进程选择一小部分大小相似的段,并且在后台将它们合并到更大的段中。这并不会中断索引和搜索。两个提交了的段和一个未提交的段正在被合并到一个更大的段。

  3. “一旦合并结束,老的段被删除” 说明合并完成时的活动:

    • 新的段被刷新(flush)到了磁盘。写入一个包含新段且排除旧的和较小的段的新提交点。
    • 新的段被打开用来搜索。
    • 老的段被删除。

合并大的段需要消耗大量的I/O和CPU资源,如果任其发展会影响搜索性能。Elasticsearch在默认情况下会对合并流程进行资源限制,所以搜索仍然 有足够的资源很好地执行。

索引

映射

为了能够将时间域视为时间,数字域视为数字,字符串域视为全文或精确值字符串, Elasticsearch 需要知道每个域中数据的类型。这个信息包含在映射中。

index属性控制索引字符串会有以下三个值:

  • analyzed: 首先分析字符串,然后索引它。换句话说,以全文索引这个域。
  • not_analyzed: 索引这个域,所以它能够被搜索,但索引的是精确值。不会对它进行分析。
  • no: 不索引这个域。这个域不会被搜索到。

查看映射

格式:GET /<INDEX>/_mapping/<TYPE>

索引

索引的分析过程

  • 字符过滤器: 首先,字符串按顺序通过每个 字符过滤器 。他们的任务是在分词前整理字符串。一个字符过滤器可以用来去掉HTML,或者将 & 转化成 and。
  • 分词器: 其次,字符串被 分词器 分为单个的词条。一个简单的分词器遇到空格和标点的时候,可能会将文本拆分成词条。
  • Token 过滤器: 最后,词条按顺序通过每个 token 过滤器 。这个过程可能会改变词条(例如,小写化 Quick ),删除词条(例如, 像 a, and, the 等无用词),或者增加词条(例如,像 jump 和 leap 这种同义词)。

内置分词器

ES还附带了可以直接使用的预包装的分析器。接下来我们会列出最重要的分析器。为了证明它们的差异,我们看看每个分析器会从下面的字符串得到哪些词条:"Set the shape to semi-transparent by calling set_trans(5)"

  • 简单分析器: 简单分析器在任何不是字母的地方分隔文本,将词条小写。它会产生set, the, shape, to, semi, transparent, by, calling, set, trans
  • 空格分析器: 空格分析器在空格的地方划分文本。它会产生Set, the, shape, to, semi-transparent, by, calling, set_trans(5)
  • 语言分析器: 特定语言分析器可用于 很多语言。它们可以考虑指定语言的特点。例如, 英语 分析器附带了一组英语无用词(常用单词,例如 and 或者 the ,它们对相关性没有多少影响),它们会被删除。 由于理解英语语法的规则,这个分词器可以提取英语单词的 词干 。英语 分词器会产生下面的词条:set, shape, semi, transpar, call, set_tran, 5 注意看 transparent、 calling 和 set_trans 已经变为词根格式。

相关性

每个文档都有相关性评分,用一个正浮点数字段 _score 来表示 。 _score 的评分越高,相关性越高。包括以下内容:

  • 检索词频率: 检索词在该字段出现的频率?出现频率越高,相关性也越高。 字段中出现过 5 次要比只出现过 1 次的相关性高。
  • 反向文档频率: 每个检索词在索引中出现的频率?频率越高,相关性越低。检索词出现在多数文档中会比出现在少数文档中的权重更低。
  • 字段长度准则: 字段的长度是多少?长度越长,相关性越低。 检索词出现在一个短的 title 要比同样的词出现在一个长的 content 字段权重更大。

创建索引

格式:

PUT /<INDEX>
{
    "settings": {
    	"number_of_shards" :   1,
        "number_of_replicas" : 0
    },
    "mappings": {
    	"TYPE": {
            "properties": {
                "PROPERTY": { 
                    "type":     "string",
                    "analyzer": "english",
                    "fields": {
                        "PROPERTY":   { 
                            "type":     "string",
                            "analyzer": "standard"
                        }
                    }
                }
            }
        }
    }
}
  • settings: 索引设置
  • number_of_shards: 每个索引的主分片数,默认值是 5 。这个配置在索引创建后不能修改。
  • number_of_replicas: 每个主分片的副本数,默认值是 1 。对于活动的索引库,这个配置可以随时修改。

如果想禁止自动创建索引,你 可以通过在 config/elasticsearch.yml 的每个节点下添加下面的配置:action.auto_create_index: false

索引 别名 就像一个快捷方式或软连接,可以指向一个或多个索引,也可以给任何一个需要索引名的API来使用。格式:PUT /<INDEX>/_alias/<INDEX>或者以下格式:

POST /_aliases
{
    "actions": [
        { "remove": { "index": "<INDEX>", "alias": "<INDEX>" }},
        { "add":    { "index": "<INDEX>", "alias": "<INDEX>" }}
    ]
}

删除索引

格式:DELETE /<INDEX>

例如:

  • DELETE /my_index:删除my_index索引
  • DELETE /index_one,index_two:删除两个索引
  • DELETE /index*:删除以index开头的索引
  • DELETE /_all与DELETE /*:删除所有索引

分布式检索过程

查询阶段

查询过程分布式搜索:

  1. 客户端发送一个 search 请求到 Node 3 , Node 3 会创建一个大小为 from + size 的空优先队列。
  2. Node 3 将查询请求转发到索引的每个主分片或副本分片中。每个分片在本地执行查询并添加结果到大小为 from + size 的本地有序优先队列中。
  3. 每个分片返回各自优先队列中所有文档的 ID 和排序值给协调节点,也就是 Node 3 ,它合并这些值到自己的优先队列中来产生一个全局排序后的结果列表。

一个索引可以由一个或几个主分片组成, 所以一个针对单个索引的搜索请求需要能够把来自多个分片的结果组合起来。 针对 multiple 或者 all 索引的搜索工作方式也是完全一致的—仅仅是包含了更多的分片而已。

取回阶段

  1. 协调节点辨别出哪些文档需要被取回并向相关的分片提交多个 GET 请求。
  2. 每个分片加载并 丰富 文档,如果有需要的话,接着返回文档给协调节点。
  3. 一旦所有的文档都被取回了,协调节点返回结果给客户端。

文档

文档元数据如下:

  • _index:一个 索引 应该是因共同的特性被分组到一起的文档集合。
  • _type:数据可能在索引中只是松散的组合在一起,但是通常明确定义一些数据中的子分区是很有用的。
  • _id:ID 是一个字符串,当它和 _index 以及 _type 组合就可以唯一确定 Elasticsearch 中的一个文档。可以自定义id如果没有指定会自动生成一个id

所有的文档 API( get 、 index 、 delete 、 bulk 、 update 以及 mget )都接受一个叫做 routing 的路由参数 ,通过这个参数我们可以自定义文档到分片的映射。

创建文档

格式:PUT /<INDEX>/<TYPE>/<ID> -d <BODY> 说明如下:

  • INDEX:索引
  • TYPE:类型
  • ID:编号
  • BODY:文档信息

更新文档

更新整个文档格式与创建文档一至,其实只是加了一个文档,返回_version比之前增加了。 文档部分更新:

POST /<INDEX>/<TYPE>/<ID>/_update
{
   "doc" : {
      "PROPERTY" : [ "VALUE" ],
      "views": 0
   }
}

得到单个文档

格式:GET /<INDEX>/<TYPE>/<ID>[?[PRETTY] [_source=PROPERTY,PROPERTY]]

得到多个文档

格式:

GET /_mget
{
   "docs" : [
      {
         "_index" : "<INDEX>",
         "_type" :  "<TYPE>",
         "_id" :    <ID>
      },
      {
         "_index" : "<INDEX>",
         "_type" :  "<TYPE>",
         "_id" :    <ID>,
         "_source": "views"
      }
   ]
}

批量操作

bulk API 允许在单个步骤中进行多次 create 、 index 、 update 或 delete 请求。

这种格式类似一个有效的单行 JSON 文档 流 ,它通过换行符(\n)连接到一起。注意两个要点:

  • 每行一定要以换行符(\n)结尾, 包括最后一行 。这些换行符被用作一个标记,可以有效分隔行。
  • 这些行不能包含未转义的换行符,因为他们将会对解析造成干扰。这意味着这个 JSON 不 能使用 pretty 参数打印。

删除文档

格式:DELETE /<INDEX>/<TYPE>/<ID>

说明:如果找到该文档,ES 将要返回一个 200 ok 的 HTTP 响应码found 是 true,并把 _version 值增加。如果文档没有找到,我们将得到 404 Not Found 的响应码 found 是 false, _version 值仍然会增加。这是 ES 内部记录本的一部分,用来确保这些改变在跨多节点时以正确的顺序执行。

轻量搜索

格式:·GET [/_all]/<INDEX>/<TYPE>/_search[?q=PROPERTY:VALUE] 解释如下:

  • PROPERTY:查询文档的属性
  • VALUE:查询属性值
  • PRETTY:调用 Elasticsearch 的 pretty-print 功能,该功能 使得 JSON 响应体更加可读
  • _source:只返回指定属性的文档
  • _all: 简单搜索返回包含 VALUE 的所有文档

返回信息说明:

  • _source:文档信息

curl -i -XHEAD <PROTOCOL>://<HOST>:<PORT>/<PATH>/<ID> 检查一个文档是否存在。HEAD 请求没有返回体,只返回一个 HTTP 请求报头;如果文档存在, ES 将返回一个 200 ok 的状态码;若文档不存在, ES 将返回一个 404 Not Found 的状态码:

查询表达式搜索

格式:

GET /INDEX/TYPE/_search[?timeout=NUMBER[&size=NUMBER][&from=NUMBER]]
{
    "query" : {
    	"prefix": {
            "postcode": "VALUE"
        },
        "wildcard": {
            "postcode": "W?F*HW" 
        },
    	"multi_match": {
        	"query":    "full text search",
        	"fields":   [ "title", "body" ]
    	},
        "match" : {
            "PROPERTY" : VALUE
        },
        "bool": {
            "must": {
                "match" : {
                    "PROPERTY" : VALUE
                }
            },
            "must_not": { "match": { "tag":   "spam" }},
            "should": [
                { "match": { "tag": "starred" }},
                { "range": { "date": { "gte": "2014-01-01" }}}
            ],
            "filter": {
                "range" : {
                    "PROPERTY" : { "gt" : VALUE }
                },
                "terms" : { 
                    "PROPERTY" : [20, 30]
                }
            }
        },
        "match_phrase" : {
            PROPERTY : VALUE
        },
        { "term": { "PROPERTY": VALUE }},
        { "terms": { "PROPERTY": [ VALUE, VALUE, VALUE ] }},
        "exists":   {
        	"field":    "PROPERTY"
    	},
    	"constant_score":   {
            "filter": {
                "term": { "category": "ebooks" } 
            }
        }
    },
    "sort": [
    	{ "PROPERTY":   { "order": "desc" }},
        { "PROPERTY": { "order": "desc" }}
    ],
    "highlight": {
        "fields" : {
            "PROPERTY" : {}
        }
    },
    "aggs": {
        "all_interests": {
          "terms": { "field": "PROPERTY" }
        },
        "aggs" : {
             "AGGSNAME" : {
                 "avg" : { "field" : "age" }
             }
         }
    }
}
  • prefix:是一个词级别的底层的查询,它不会在搜索之前分析查询字符串,它假定传入前缀就正是要查找的前缀。

  • wildcard: 通配符查询也是一种底层基于词的查询,与前缀查询不同的是它允许指定匹配的正则式。它使用标准的 shell 通配符查询: ? 匹配任意字符, * 匹配 0 或多个字符。

  • term: 用于精确值匹配,这些精确值可能是数字、时间、布尔或者那些 not_analyzed 的字符串

  • terms:和 term 查询一样,但它允许你指定多值进行匹配。如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件

  • constant_score: 将一个不变的常量评分应用于所有匹配的文档。它被经常用于你只需要执行一个 filter 而没有其它查询(例如,评分查询)的情况下。term 查询被放置在 constant_score 中,转成不评分的 filter。这种方式可以用来取代只有 filter 语句的 bool 查询。

  • match: 标准查询

  • multi_match:查询为能在多个字段上反复执行相同查询提供了一种便捷方式。

  • range:查询找出那些落在指定区间内的数字或者时间;可使用的操作符:

    gt大于 gte大于等于 lt小于 lte小于等于

  • match_phrase:精确匹配一系列单词或者短语

  • bool: 多查询组合在一起

  • must: 文档 必须 匹配这些条件才能被包含进来。

  • must_not: 文档 必须不 匹配这些条件才能被包含进来。

  • should: 如果满足这些语句中的任意语句,将增加 _score ,否则,无任何影响。它们主要用于修正每个文档的相关性得分。

  • filter: 必须 匹配,但它以不评分、过滤模式来进行。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档。

  • highlight:高亮显示匹配文本片段

  • all_interests:聚合与 SQL 中的 GROUP BY 类似

  • aggname:聚合名称

  • timeout: 设置查询超时时间

  • size: 显示应该返回的结果数量,默认是 10

  • from: 显示应该跳过的初始结果数量,默认是 0

  • sort: 排序

  • exists与missing: 被用于查找那些指定字段中有值 (exists) 或无值 (missing) 的文档

返回说明:

  • _score:相关性得分
  • hits: 包含 total 字段来表示匹配到的文档总数
  • took:值告诉我们执行整个搜索请求耗费了多少毫秒
  • _shards:告诉我们在查询中参与分片的总数,以及这些分片成功了多少个失败了多少个。
  • timed_out:是否超时。默认情况下,搜索请求不会超时。如果低响应时间比完成结果更重要,你可以指定 timeout 为 10 或者 10ms(10毫秒),或者 1s(1秒)

查询可以变得非常的复杂,尤其和不同的分析器与不同的字段映射结合时,理解起来就有点困难了。可以通过GET /<INDEX>/<TYPE>/_validate/query -D <BODY>

经常的情况下,你想在一个或多个特殊的索引并且在一个或者多个特殊的类型中进行搜索。我们可以通过在URL中指定特殊的索引和类型达到这种效果,如下所示:

  • /_search: 在所有的索引中搜索所有的类型
  • /gb/_search: 在 gb 索引中搜索所有的类型
  • /gb,us/_search: 在 gb 和 us 索引中搜索所有的文档
  • /g,u/_search: 在任何以 g 或者 u 开头的索引中搜索所有的类型
  • /gb/user/_search: 在 gb 索引中搜索 user 类型
  • /gb,us/user,tweet/_search: 在 gb 和 us 索引中搜索 user 和 tweet 类型
  • /all/user,tweet/search: 在所有的索引中搜索 user 和 tweet 类型

短语查询和邻近查询都比简单的 query 查询代价更高。 一个 match 查询仅仅是看词条是否存在于倒排索引中,而一个 match_phrase 查询是必须计算并比较多个可能重复词项的位置。一个简单的 term 查询比一个短语查询大约快 10 倍,比邻近查询(有 slop 的短语 查询)大约快 20 倍。当然,这个代价指的是在搜索时而不是索引时。

过滤器内容操作

在内部,ES 会在运行非评分查询的时执行多个操作:

  1. 查找匹配文档
  2. 创建 bitset:过滤器会创建一个 bitset (一个包含 0 和 1 的数组),它描述了哪个文档会包含该 term 。匹配文档的标志位是 1 。
  3. 迭代 bitset(s):一旦为每个查询生成了 bitsets ,Elasticsearch 就会循环迭代 bitsets 从而找到满足所有过滤条件的匹配文档的集合。执行顺序是启发式的,但一般来说先迭代稀疏的 bitset (因为它可以排除掉大量的文档)。
  4. 增量使用计数:能够缓存非评分查询从而获取更快的访问,但是它也会不太聪明地缓存一些使用极少的东西。非评分计算因为倒排索引已经足够快了,所以我们只想缓存那些我们 知道 在将来会被再次使用的查询,以避免资源的浪费。为了实现以上设想,Elasticsearch 会为每个索引跟踪保留查询使用的历史状态。如果查询在最近的 256 次查询中会被用到,那么它就会被缓存到内存中。当 bitset 被缓存后,缓存会在那些低于 10,000 个文档(或少于 3% 的总索引数)的段(segment)中被忽略。这些小的段即将会消失,所以为它们分配缓存是一种浪费。

 

备案号:豫ICP备14002392号-2