vlambda博客
学习文章列表

读书笔记《elasticsearch-server-third-edition》Elasticearch集群入门

Chapter 1. Getting Started with Elasticsearch Cluster

欢迎来到 Elasticsearch 的精彩世界——一个出色的全文搜索和分析引擎。如果您不熟悉 Elasticsearch 和一般的全文搜索,或者您已经有这方面的经验,这并不重要。我们希望通过阅读本书,您将能够学习和扩展您对 Elasticsearch 的了解。由于这本书也是为初学者准备的,我们决定先简要介绍一下全文搜索,然后再简要介绍一下 Elasticsearch。

请记住,Elasticsearch 是一个快速变化的软件。不仅增加了功能,而且 Elasticsearch 的核心功能也在不断发展和变化。我们努力跟上这些变化,因此我们为您提供了专门介绍 Elasticsearch 2.x 的第三版。

我们需要对 Elasticsearch 做的第一件事是安装和配置它。对于许多应用程序,您从安装和配置开始,通常会忘记这些步骤的重要性。我们将尝试指导您完成这些步骤,以便更容易记住。除此之外,我们将向您展示索引和检索数据的最简单方法,而无需过多详细说明。第一章将带您快速了解 Elasticsearch 和全文搜索世界。在本章结束时,您将学习以下主题:

  • 全文检索

  • Apache Lucene 的基础知识

  • 执行文本分析

  • Elasticsearch 的基本概念

  • 安装和配置 Elasticsearch

  • 使用 Elasticsearch REST API 操作数据

  • 使用基本 URI 请求进行搜索

Full text searching


回到全文搜索是一小部分工程师知道的术语的时代,我们大多数人使用 SQL 数据库来执行搜索操作。使用 SQL 数据库搜索存储在其中的数据在某种程度上是可以的。这样的搜索并不快,尤其是在大量数据上。即使是现在,小型应用程序通常也可以在 SQL 数据库中使用标准的 LIKE %phrase% 搜索。然而,随着我们越来越深入,我们开始看到这种方法的局限性——缺乏可扩展性、不够灵活以及缺乏语言分析。当然,还有一些额外的模块可以扩展 SQL 数据库的全文搜索功能,但与专用的全文搜索库和 Elasticsearch 等搜索引擎相比,它们仍然有限。其中一些原因导致了 Apache Lucene (http://lucene.apache.org/),一个完全用 Java 编写的库 (http://java.com/en/),速度非常快,轻量级,并提供语言分析适用于世界各地使用的大量语言。

The Lucene glossary and architecture

在进入分析过程的细节之前,我们想向您介绍Apache Lucene的词汇表和整体架构。我们决定这些信息对于理解 Elasticsearch 的工作原理至关重要,尽管这本书不是关于 Apache Lucene,但要了解 Elasticsearch 分析的基础和索引引擎对于充分了解这个伟大的搜索引擎是如何工作的至关重要。

上述库的基本概念如下:

  • Document:这是索引和搜索过程中使用的主要数据载体,包含一个或多个字段,这些字段包含我们输入和从 Lucene 获取的数据。

  • Field:这是文档的一个部分,由两个部分:名称和值。

  • Term:这是一个 搜索的单位,代表文本中的一个词.

  • Token:这是一个在文本中出现的术语场地。它由术语文本、开始和结束偏移量以及类型组成。

Apache Lucene 将所有 信息写入一个名为倒排索引 的结构中。它是一种将索引中的术语映射到文档的数据结构,而不是像关系数据库在其表中所做的那样。您可以将倒排索引视为一种数据结构,其中数据是面向术语而不是面向文档的。让我们看看一个简单的倒排索引会是什么样子。例如,假设我们有一个文档只有一个名为 title 的字段被索引,该字段的值如下:

  • Elasticsearch 服务器(文档 1)

  • 精通 Elasticsearch 第二版(文档 2)

  • Apache Solr Cookbook 第三版(文档 3)

Lucene 倒排索引 的非常简化的可视化如下所示:

读书笔记《elasticsearch-server-third-edition》Elasticearch集群入门

每个术语都指向它所在的文档数量。例如,术语 edition 在第二个和第三个文档中出现了两次。这种结构允许在基于术语的查询中进行非常有效和快速的搜索操作(但不限于)。因为术语的 出现与术语本身相关联,Lucene 可以使用有关术语出现的信息来执行快速准确的评分信息,方法是为每个文档提供一个表示每个返回的文档与查询匹配程度的值。

当然,由 Lucene 创建的实际索引要复杂和高级得多,因为附加文件包括诸如术语向量(每个文档的倒排索引)、文档值(面向列的字段信息)、存储字段(原始而不是字段的分析值),等等。但是,您现在只需要知道数据是如何组织的,而不是存储的具体内容。

每个索引分为 多个一次写入和多次读取的结构,称为段。每个 segment 都是 自己的微型 Apache Lucene 索引。索引时,单个segment写入磁盘后不能更新,或者说不能完全更新;文档无法从中删除,只能在单独的文件中标记为已删除。 Lucene 不允许 segments 更新的原因是倒排索引的性质。在字段被分析并放入倒排索引之后,没有简单的方法构建原始文档结构。删除时,Lucene 必须从段中删除信息,这意味着更新倒排索引本身内的所有信息。

由于段是一次写入结构,Lucene 能够在称为段合并的过程中将段合并在一起。在索引期间,如果 Lucene 认为有太多的段落入相同的标准,将创建一个新的更大的段 - 一个将包含来自其他段的数据。在此过程中,Lucene 将尝试删除已删除的数据并取回保存有关这些文档的信息所需的空间。段合并在 I/O 和 CPU 方面都是一项要求很高的操作。我们现在必须记住的是,使用一个大段进行搜索比使用多个持有相同数据的较小段进行搜索要快。这是因为,一般来说,搜索只是将查询词与被索引的词进行匹配。您可以想象搜索多个小段并合并这些结果将比使用单个段准备结果要慢得多。

Input data analysis

一个文档来到 Lucene,经过处理,放入倒排索引 格式的转换称为indexation 。在此期间 Lucene 必须做的一件事是数据分析。您可能希望某些字段由语言分析器 处理,以便诸如 car 和 汽车被视为与您的索引相同。另一方面,您可能希望其他字段仅按空格字符划分或仅小写。

分析由分析器完成,分析器由分词器和零个或多个分词过滤器构成,它也可以有零个或多个字符映射器。

Lucene 中的分词器是 用于将文本拆分为令牌,这些令牌基本上是带有附加信息的术语,例如其在原始文本中的位置和长度。标记器工作的结果称为标记流,其中标记被一一放置并准备好由过滤器处理。

除了标记器,Lucene 分析器由零个或多个标记过滤器构建,用于处理标记流中的标记。过滤器的一些示例如下:

  • 小写过滤器:使所有标记小写

  • 同义词过滤器根据同义词规则将一个标记更改为另一个

  • Language stemming filters负责减少token(其实就是文本部分他们提供的) 到称为词干 (https://en. wikipedia.org/wiki/Word_stem

过滤器是一个接一个地处理,所以我们有几乎无限的分析可能性加上 多个过滤器,一个接一个。

最后,字符映射器对未分析的文本进行操作——它们在分词器之前使用。因此,我们可以轻松地从整个文本部分中删除 HTML 标记,而无需担心标记化。

Indexing and querying

您可能想知道,到目前为止,我们所描述的所有 信息在使用 Lucene 和基于它构建的所有软件时如何影响索引和查询。在索引期间,Lucene 将使用您选择的分析器来处理您的 文档的内容;当然,不同的分析器可以用于不同的字段,因此与汇总字段相比,可以对文档的名称字段进行不同的分析。例如,名称字段可能仅在空格上标记化并小写,以便完成完全匹配并且除此之外对摘要字段进行词干处理。我们也可以决定根本不分析这些字段——我们可以完全控制分析过程。

在查询期间,您的查询文本也可以被分析。但是,您也可以选择不分析您的查询。记住这一点很重要,因为有些 Elasticsearch 查询会被分析,而有些则不会。例如,不分析前缀和术语查询,而分析匹配查询(我们将在 Chapter 3, 搜索您的数据)。分析和未分析的查询非常有用;有时,您可能想要查询未分析的字段,而有时您可能想要进行全文搜索分析。例如,如果我们搜索 LightRed 术语并且标准分析器正在分析查询,那么将要搜索的术语是浅红色的。如果我们使用尚未分析的查询类型,那么我们将显式搜索 LightRed 术语。如果我们只对精确匹配感兴趣,我们可能不想分析查询的内容。

关于索引和查询分析,您应该记住的是索引应该与查询词匹配。如果它们不匹配,Lucene 将不会返回所需的文档。例如,如果您在索引期间使用词干和小写,则需要确保查询中的术语也是小写和词干,否则您的查询将根本不会返回任何结果。例如,让我们回到我们在索引期间分析的 LightRed 术语;我们将它 作为索引中的两个术语:lightred 。如果我们针对该数据运行 LightRed 查询 并且不对其进行分析,我们将不会得到结果中的文档 - query 术语与索引术语不匹配。在索引和查询时间分析期间保持标记过滤器的顺序相同很重要,这样分析产生的术语是相同的。

Scoring and query relevance

还有一件事我们到目前为止只提到过一次——得分。文件的分数是多少?该分数是一个评分公式的结果,该公式描述了文档如何与查询匹配。默认情况下,Apache Lucene 使用 TF/IDF(词频/逆文档频率)评分机制,这是一种计算文档在我们查询上下文中的相关程度的算法。当然,它不是唯一可用的算法,我们将在 Mappings configuration 部分提到其他算法="#" linkend="ch02">第 2 章索引您的数据

Note

如果您想了解更多关于 Apache Lucene TF/IDF 评分公式的信息,请访问 Apache Lucene Javadocs 获取 TFIDF。相似类可在 http://lucene.apache.org/core/5_4_0/core/org/apache/lucene/search/similarities/TFIDFSimilarity.html

The basics of Elasticsearch


Elasticsearch 是由 Shay Banon 发起并于 2010 年 2 月发布的开源搜索服务器项目。在此期间,该项目成长为搜索和数据领域的主要参与者 < /a>分析解决方案,广泛用于许多常见或鲜为人知的搜索和数据分析平台。此外,由于其分布式特性和实时搜索和分析功能,许多组织将其用作文档存储。

Key concepts of Elasticsearch

在接下来的几页中,我们将带您了解 Elasticsearch 的基本概念。如果您已经熟悉 Elasticsearch 架构,则可以跳过此部分。但是,如果您不熟悉 Elasticsearch,我们强烈建议您阅读本节。我们将在本书的其余部分引用本节中使用的关键词,理解这些概念对于充分利用 Elasticsearch 至关重要。

Index

索引是 Elasticsearch 存储数据的 逻辑位置。每个索引可以分布在多个 Elasticsearch 节点上,并被分成一个或多个称为 shards 的小块,它们是 物理放置在硬盘上。如果您 来自关系数据库世界,您可以将索引视为表。但是,索引结构为快速高效的全文搜索做好了准备,特别是, 不存储原始值。该结构称为倒排索引(https://en.wikipedia.org/wiki/倒排索引)。

如果您了解 MongoDB,您可以将 Elasticsearch 索引视为 MongoDB 中的一个集合。如果您熟悉 CouchDB,则可以像考虑 CouchDB 数据库一样考虑索引。 Elasticsearch 可以在一台机器上保存许多索引,也可以将它们分布在多台服务器上。正如我们已经说过的,每个索引都是由一个或多个分片构建的,每个分片可以有很多副本。

Document

Elasticsearch 中存储的主要实体是一个文档。一个文档可以有多个字段,每个字段都有自己的类型并进行不同的处理。类比 关系数据库,文档是数据库表中的一行数据。当您将 Elasticsearch 文档与 MongoDB 文档进行比较时,您会发现两者可以具有不同的结构。谈到 Elasticsearch 时要记住的是,同一索引中多个类型共有的字段需要具有相同的类型。这意味着所有具有标题字段的文档都需要具有相同的数据类型,例如字符串。

文档由字段组成,每个字段在单个文档中可能出现多次(这样的字段是,称为多值)。每个字段都有一个类型(文本、数字、日期等)。字段类型也可以很复杂——一个字段可以包含其他子文档或数组。字段类型对 Elasticsearch 很重要,因为类型决定了如何执行分析或排序等各种操作。幸运的是,这可以自动确定(但是,我们仍然建议使用映射;看看下面的内容)。

与关系数据库不同,文档不需要有固定的结构——每个文档可能有不同的字段集,除此之外,在应用程序开发期间不必知道字段。当然,可以使用模式强制文档 结构。从客户端的角度来看,文档是 JSON 对象(请参阅 https://en.wikipedia.org/wiki/JSON)。每个文档都存储在一个索引中,并具有自己的唯一标识符,该标识符可以由 Elasticsearch 自动生成,以及文档类型。要记住的是文档标识符在索引中必须是唯一的 并且应该是给定类型的。这意味着,在单个索引中,如果两个文档 的类型不同,则它们可以具有相同的唯一标识符。

Document type

在 Elasticsearch 中,一个索引 可以存储许多用于不同目的的对象。例如,博客应用程序 可以存储文章和评论。文档类型让我们可以轻松区分单个索引中的对象。每个文档都可以有不同的结构,但在实际部署中,将文档划分为类型显着有助于数据操作。当然,需要牢记这些限制。也就是说,不同的文档类型不能为同一个属性设置不同的类型。例如,一个名为 title 的字段必须在给定索引中的所有文档类型中具有相同的类型。

Mapping

在关于全文搜索基础的部分(全文搜索部分)中,我们写了关于 分析过程——为底层 Apache Lucene 库完成的索引和搜索准备输入文本。必须根据其类型正确分析文档的每个字段。例如,对于数字字段(数字不应按字母顺序排序)和从网页获取的文本(例如,第一步将要求您省略 HTML 标签,因为它是无用的信息)。为了能够在索引和查询时进行正确分析,Elasticsearch 将有关文档字段的信息存储在所谓的映射中。每个文档类型都有自己的映射,即使我们没有明确定义它。

Key concepts of the Elasticsearch infrastructure

现在,我们已经知道 Elasticsearch 将其数据存储在一个或多个索引中,每个索引都可以包含各种类型的文档。我们还知道每个文档都有很多字段,而 Elasticsearch 如何处理这些字段是由映射定义的。但还有更多。从一开始,Elasticsearch 就被创建为一个分布式解决方案,每秒可以处理数十亿个文档和数百个搜索请求。这是由于我们现在将更详细地描述的几个重要的关键特性和概念。

Nodes and clusters

Elasticsearch 可以 作为独立的单一搜索服务器工作。尽管如此,要 能够处理大量数据 并实现容错和高可用性,Elasticsearch 可以在许多协作服务器上运行。这些连接在一起的服务器统称为集群,构成集群的每台服务器称为节点。

Shards

当我们有大量文档时,我们可能会遇到单个节点可能不够用的地步——以 为例,由于 RAM 的限制,很难磁盘容量、处理能力不足以及无法足够快地响应客户端请求。在这种情况下,索引(以及其中的数据)可以分为 更小的部分,称为 shards< /strong>(其中每个分片是一个单独的 Apache Lucene 索引)。每个分片可以放置在不同的服务器上,因此您的数据可以在集群节点之间传播。当您查询从多个分片构建的索引时,Elasticsearch 会将查询发送到每个相关分片并以您的应用程序不知道分片的方式合并结果。除此之外,拥有多个分片可以加快索引速度,因为文档最终位于不同的分片中,因此索引操作是并行化的。

Replicas

为了提高查询 吞吐量或实现高可用性,可以使用分片副本。副本只是分片的精确副本,每个分片 可以有零个或多个副本。换句话说,Elasticsearch 可以有许多相同的分片,其中一个会自动选择作为更改索引的操作所指向的位置。这个特殊的分片称为主分片,其他分片称为副本分片。当主分片丢失时(例如,持有分片数据的服务器不可用),集群会将副本提升为新的主分片。

Gateway

集群状态由网关持有,网关存储集群状态并被索引整个集群中的数据重新启动。默认情况下,每个节点都将这些信息存储在本地;它在节点之间同步。我们将在 网关和恢复模块 部分讨论网关模块>第 9 章Elasticsearch 集群,详细说明。

Indexing and searching

您可能想知道如何将所有索引、分片和副本绑定在一个环境中。从理论上讲,当您必须知道文档在哪里时,从 集群中获取数据是非常困难的:在哪个服务器上以及在哪个分片中。当一个查询可以从放置在整个集群中不同节点上的不同分片中返回文档时,搜索将变得更加困难。事实上,这是一个复杂的问题;幸运的是,我们根本不需要关心这个——它由 Elasticsearch 自动处理。我们来看下图:

读书笔记《elasticsearch-server-third-edition》Elasticearch集群入门

当您将新文档发送到集群时,您指定一个目标索引并将其发送到任何节点。 节点知道目标索引有多少分片,并且能够确定应该使用哪个分片来存储您的文档。 Elasticsearch 可以改变这种行为;我们将在章节的路由简介部分讨论这个问题2索引您的数据。您现在必须记住的重要信息是 Elasticsearch 使用文档的唯一标识符来计算应该放置文档的分片 - 这是每个文档需要 唯一标识符。索引请求发送到节点后,该节点将文档转发到目标节点,目标节点托管 相关分片。

现在,让我们看一下搜索请求执行的下图:

读书笔记《elasticsearch-server-third-edition》Elasticearch集群入门

当您尝试通过其标识符获取文档时,您发送查询的节点使用相同的路由算法来确定分片和保存文档的节点,然后再次转发请求,获取结果,并将结果发送给您。另一方面,查询过程是一个更复杂的过程。接收查询的节点将其转发给所有节点 持有属于给定索引的分片,并要求有关与查询匹配的文档的最少信息(标识符和分数默认匹配),除非使用路由,否则查询将直接转到单个分片。这称为散射阶段。收到此信息后,聚合器节点(接收客户端请求的节点)对结果进行排序并发送第二个请求以获取构建结果列表所需的文档(除了文档标识符和分数之外的所有其他信息) .这称为收集阶段。此阶段执行后,将结果返回给客户端。

现在问题来了:副本在前面描述的过程中的作用是什么?在建立索引时,副本仅用作存储数据的附加位置。在执行查询时,默认情况下,Elasticsearch 会尝试平衡分片及其副本之间的负载,以使它们受到均匀的压力。另外,请记住我们可以改变这种行为;我们将在章节的了解查询过程部分讨论这个问题3搜索您的数据

Installing and configuring your cluster


那是在 Elasticsearch 0.20.x 时代。从尚未准备好的系统到使用 Elasticsearch 的系统,只需执行几个步骤。我们将在以下部分探讨这些步骤:

Installing Java

Elasticsearch 是一个 Java 应用程序,要使用它,我们需要确保 Java SE 环境< /a> 已正确安装。 Elasticsearch 需要 Java 版本 7 或更高版本才能运行。您可以从 http://www.oracle 下载它.com/technetwork/java/javase/downloads/index.html。你也可以使用 OpenJDK ( http://openjdk.java.net/)如果你愿意的话。当然,您可以使用 Java 版本 7,但 Oracle 不再支持它,至少没有商业支持。例如,您不能期望 Java 7 的新补丁版本会发布。正因为如此,我们强烈建议您安装 Java 8,尤其是考虑到 Java 9 似乎指日可待,一般可用性计划于 2016 年 9 月发布。

Installing Elasticsearch

要安装 Elasticsearch 您只需要转到 https://www.elastic.co/downloads/elasticsearch,选择最后一个稳定版本的Elasticsearch,下载,解压。而已!安装完成。

Note

在编写 时,我们使用了 Elasticsearch 2.2 的快照。这意味着我们已经跳过了描述一些被标记为弃用的属性,并且在未来的 Elasticsearch 版本中将被删除。

与 Elasticsearch 通信的主要接口基于 HTTP 协议和 REST。这意味着您甚至可以使用网络浏览器进行一些基本查询和请求,但对于更复杂的事情,您需要使用额外的软件,例如 cURL 命令。如果您使用 Linux 或 OS X 命令,cURL 包应该已经可用。如果你使用 Windows,你可以从 http://curl.haxx.se 下载包/download.html

Running Elasticsearch

让我们运行我们刚刚下载为 ZIP 存档并解压缩的第一个实例。转到 bin 目录并根据操作系统运行以下命令:

  • LinuxOS X./elasticsearch

  • Windowselasticsearch.bat

恭喜!现在,您的 Elasticsearch 实例已启动并运行。服务器在工作期间通常使用两个端口号:第一个用于使用 HTTP 协议与 REST API 通信,第二个用于传输模块,用于集群中以及本地 Java 客户端与集群之间的通信。 HTTP API 使用的默认端口是 9200,因此我们可以通过将 Web 浏览器指向 http://127.0.0.1:9200/ 来检查搜索准备情况。浏览器应显示类似于以下的代码片段:

{
  "name" : "Blob",
  "cluster_name" : "elasticsearch",
  "version" : {
    "number" : "2.2.0",
    "build_hash" : "5b1dd1cf5a1957682d84228a569e124fedf8e325",
    "build_timestamp" : "2016-01-13T18:12:26Z",
    "build_snapshot" : true,
    "lucene_version" : "5.4.0"
  },
  "tagline" : "You Know, for Search"
}

输出结构为 JavaScript Object Notation (JSON)目的。如果您不熟悉 JSON,请花一点时间 阅读https://en.wikipedia.org/wiki/JSON

Note

Elasticsearch 很聪明。如果默认端口不可用,引擎将绑定到下一个空闲端口。您可以在引导期间在控制台上找到有关此的信息,如下所示:

[2016-01-13 20:04:49,953][INFO ][http] [Blob] publish_address {127.0.0.1:9201}, bound_addresses {[fe80::1]:9200}, {[::1]:9200}, {127.0.0.1:9201} 

请注意带有 [http] 的片段。 Elasticsearch 使用几个端口来完成各种任务。我们使用的接口由 HTTP 模块处理。

现在,我们将使用 cURL 程序与 Elasticsearch 进行通信。例如,要检查集群健康状况,我们将使用以下命令:

curl -XGET http://127.0.0.1:9200/_cluster/health?pretty

-X 参数是HTTP请求方法的定义。默认值为 GET (因此在本例中,我们可以省略此参数)。现在,不要担心 GET 值;我们将在本章后面更详细地描述它。

作为标准,API 以 JSON 对象的形式返回信息,其中省略了换行符。添加到我们的请求中的 pretty 参数强制 Elasticsearch 在响应中添加换行符,使响应更加用户友好。您可以尝试使用和不使用 ?pretty 参数运行上述查询以查看差异。

Elasticsearch 在 中小型应用程序中很有用,但它在构建时考虑到了大型集群。所以,现在我们将建立我们的大型两节点集群。将 Elasticsearch 存档解压缩到不同的目录并运行第二个实例。如果我们查看日志,我们将看到以下内容:

[2016-01-13 20:07:58,561][INFO ][cluster.service          ] [Big Man] detected_master {Blob}{5QPh00RUQraeLHAInbR4Jw}{127.0.0.1}{127.0.0.1:9300}, added {{Blob}{5QPh00RUQraeLHAInbR4Jw}{127.0.0.1}{127.0.0.1:9300},}, reason: zen-disco-receive(from master [{Blob}{5QPh00RUQraeLHAInbR4Jw}{127.0.0.1}{127.0.0.1:9300}])

这意味着我们的第二个实例(名为 Big Man)发现了之前运行的实例(名为 Blob)。在这里,Elasticsearch 自动形成了一个新的两节点集群。从 Elasticsearch 2.0 开始,这仅适用于在同一物理机器上运行的节点——因为 Elasticsearch 2.0 不再支持多播。要允许您的集群形成,您需要使用 discovery.zen.ping.unicast.hosts 数组通知 Elasticsearch 最初应该联系的节点文字">elasticsearch.yml。例如,像这样:

discovery.zen.ping.unicast.hosts: ["192.168.2.1", "192.168.2.2"]

Shutting down Elasticsearch

尽管我们希望我们的 集群(或节点)能够完美运行一生,但我们可能需要重新启动它或正确关闭它(例如,维护)。以下是我们可以关闭 Elasticsearch 的两种方式:

  • 如果您的节点连接到控制台,只需按 Ctrl + C

  • 第二种选择是通过发送 TERM 信号来终止服务器进程(参见 Linux 机器上的 kill 命令和 Windows 上的程序管理器)

    Note

    以前版本的 Elasticsearch 公开了一个专用的关闭 API,但在 2.0 中,出于安全原因,此选项已 被删除。

The directory layout

现在,让我们进入新创建的目录。我们应该看到以下目录结构:

目录

描述

Bin

运行 Elasticsearch 实例和插件管理所需的 脚本

配置

配置文件所在的目录

Elasticsearch 使用的

模块

与 Elasticsearch 捆绑的 插件

Elasticsearch 启动后,它会创建以下目录(如果它们不存在):

目录

描述

数据

Elasticsearch用来存储所有数据的目录

日志

包含有关事件和错误信息的文件

插件

存储已安装插件的 位置

工作

Elasticsearch 使用的 临时文件

Configuring Elasticsearch

Elasticsearch 越来越受欢迎的原因之一——当然,不是唯一的原因——是 Elasticsearch 的入门非常容易。由于简单环境的合理默认值和自动设置,我们可以跳过配置直接进入索引和查询(或本书的下一章)。我们可以在不更改配置文件中的任何一行的情况下完成所有这些操作。但是,为了真正了解 Elasticsearch,有必要了解一些可用的设置。

我们现在将探索 Elasticsearch tar.gz 存档提供的默认目录和文件布局。整个配置位于 config 目录中。我们可以在此处看到两个文件:elasticsearch.yml(或 elasticsearch.json,如果存在将使用)和 logging.yml。第一个文件负责设置服务器的默认配置值。这很重要,因为其中一些值可以在运行时 更改,并且可以作为集群状态的一部分保留,因此该文件中的值可能不会准确。我们无法在运行时更改的两个值是 cluster.namenode.name

cluster.name 属性负责保存我们集群的名称。集群名称将不同的集群彼此分开。配置有相同集群名称的节点将尝试形成集群。

第二个值是实例(node.name 属性)名称。我们可以不定义这个参数。在这种情况下,Elasticsearch 会自动为自己选择一个唯一的名称。请注意,此名称是在每次启动期间选择的,因此每次重新启动时名称可能不同。在通过 API 引用具体实例或使用监控工具查看节点在很长一段时间内和重启之间发生的情况时,定义名称会很有帮助。考虑为您的节点提供描述性名称。

其他参数在文件中注释很好,建议您仔细查看;如果您不理解解释,请不要担心。我们希望在阅读接下来的几章后,一切都会变得更加清晰。

Note

请记住,在 elasticsearch.yml 文件中设置的大部分参数都可以使用 Elasticsearch REST API 进行覆盖。我们将在 更新设置 API 部分讨论这个 API第 9 章Elasticsearch 集群详解

第二个文件(logging.yml)定义了将多少信息写入系统日志,定义日志文件,并定期创建新文件。通常只有在需要适应监控或备份方案或者系统调试时才需要修改这个文件;但是,如果您想要更详细的日志记录,则需要相应地进行调整。

让我们暂时放下配置文件,看看所有应用程序的基础——操作系统。调整您的操作系统是确保您的 Elasticsearch 实例运行良好的关键点之一。在索引期间,尤其是当有很多分片和副本时,Elasticsearch 会创建很多文件;因此,系统无法将打开的文件描述符限制在 32,000 以下。对于 Linux 服务器,这通常可以在 /etc/security/limits.conf 中更改,并且可以使用 ulimit 命令。如果最终达到限制,Elasticsearch 将无法创建新文件;所以 合并会失败,索引可能会失败,并且不会创建新的索引。

Note

在 Microsoft Windows 平台上,默认限制是每个进程超过 1600 万个句柄,这应该绰绰有余。您可以在 https://blogs.technet.microsoft.com/markrussinovich/2009/09/29/pushing -the-limits-of-windows-handles/

下一组设置连接到 Java 虚拟机(< span class="strong">JVM) 单个 Elasticsearch 实例的堆内存限制。对于小型部署,默认内存限制 (1,024 MB) 就足够了,但对于大型部署就不够了。如果您发现指示 OUTOFMEMORYERROR 异常的条目,请在选择大于1024的值中设置 es_heap_size 变量。分配给 JVM 的正确内存大小,请记住,一般来说,分配的内存不应超过总系统内存的 50%。但是,与所有规则一样,也有例外。稍后我们将更详细地讨论这一点,但您应该始终监控您的 JVM 堆使用情况并在需要时进行调整。

The system-specific installation and configuration

尽管使用 Elasticsearch 下载 存档并解压它可以工作并且便于测试,但有一些专用于 Linux 操作系统的方法可以在您进行生产时为您提供一些优势部署。在生产部署中,Elasticsearch 服务应该在系统启动时自动运行;我们应该有专门的启动和停止脚本、统一的路径等等。 Elasticsearch 支持我们可以使用的各种 Linux 发行版的安装包。让我们看看这是如何工作的。

Installing Elasticsearch on Linux

在 Linux 操作系统上安装 Elasticsearch 的另一种方法 是使用 RPM 或 DEB 等软件包,具体取决于您的 Linux 发行版和支持的软件包类型。这种方式我们可以自动适应系统目录布局;例如,配置和日志将放在 /etc/ 或 /var/log 目录中的标准位置。但这不是唯一的事情。在使用包时,Elasticsearch 还会安装启动脚本,让我们的生活更轻松。更重要的是,我们将能够通过从命令行运行单个命令轻松升级 Elasticsearch。当然,这些包可以在我们之前谈到从 ziptar.gz 安装 Elasticsearch 时提到的相同 URL 地址找到 包:https://www.elastic.co/downloads/elasticsearch< /一>。 Elasticsearch 也可以从远程存储库通过标准分发工具安装,例如 apt-get百胜

Note

在安装 Elasticsearch 之前,请确保您安装了正确版本的 Java 虚拟机。

Installing Elasticsearch using RPM packages

在使用支持 RPM 包 的 Linux 发行版(例如 Fedora Linux)时,(< a class="ulink" href="https://getfedora.org/" target="_blank">https://getfedora.org/) Elasticsearch 安装非常简单。下载完RPM包后,我们只需要以root身份运行以下命令即可:

yum elasticsearch-2.2.0.noarch.rpm

或者,您可以添加远程存储库并从中安装 Elasticsearch(此命令也需要以 root 身份运行):

rpm --import https://packages.elastic.co/GPG-KEY-elasticsearch

此命令添加 GPG 密钥并允许系统验证获取的包是否确实来自 Elasticsearch 开发人员。第二步,我们需要在 /etc/yum.repos.d/elasticsearch.repo 文件中创建存储库定义。我们需要在该文件中添加以下条目:

[elasticsearch-2.2]
name=Elasticsearch repository for 2.2.x packages
baseurl=http://packages.elastic.co/elasticsearch/2.x/centos
gpgcheck=1
gpgkey=http://packages.elastic.co/GPG-KEY-elasticsearch
enabled=1

现在是时候安装 Elasticsearch 服务器了,只需运行以下命令即可(同样,不要忘记以 root 身份运行它):

yum install elasticsearch

Elasticsearch 将自动下载、验证和安装。

Installing Elasticsearch using the DEB package

当使用一个支持 DEB包(如Debian)的Linux发行版时,安装Elasticsearch 再次变得非常简单。下载 DEB 包后,您需要做的就是运行以下命令:

sudo dpkg -i elasticsearch-2.2.0.deb

它是如此简单。另一种方法与我们对 RPM 包所做的类似,是创建一个新的包源并从远程存储库安装 Elasticsearch。第一步是添加用于包验证的公共 GPG 密钥。我们可以使用以下命令来做到这一点:

wget -qO - https://packages.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -

第二步是 添加DEB包位置。我们需要将以下行添加到 /etc/apt/sources.list 文件中:

deb http://packages.elastic.co/elasticsearch/2.2/debian stable main

这定义了 Elasticsearch 包的 源。最后一步是更新远程包列表并使用以下命令安装 Elasticsearch:

sudo apt-get update && sudo apt-get install elasticsearch
Elasticsearch configuration file localization

使用包安装 Elasticsearch 时,配置文件的目录与默认的 conf 目录略有不同。安装完成后,配置文件 应存放在以下位置:

  • /etc/sysconfig/elasticsearch/etc/default/elasticsearch:作为用户配置 Elasticsearch 进程的文件作为日志、数据和内存设置的目录运行

  • /etc/elasticsearch/:Elasticsearch 配置文件的目录,例如 elasticsearch.yml 文件

Configuring Elasticsearch as a system service on Linux

如果一切顺利,您可以使用以下命令运行 Elasticsearch:

/bin/systemctl start elasticsearch.service

如果您希望 Elasticsearch 在每次操作系统启动时自动启动,您可以通过运行以下命令将 Elasticsearch 设置为系统服务:

/bin/systemctl enable elasticsearch.service

Elasticsearch as a system service on Windows

在 Windows 上安装 Elasticsearch 作为系统服务也很容易。您只需要进入您的 Elasticsearch 安装目录,然后进入 bin 子目录,并运行以下命令:

service.bat install

系统会要求您允许这样做。如果您允许脚本运行,Elasticsearch 将作为 Windows 服务安装。

如果您想查看 service.bat 脚本文件公开的所有命令,只需运行以下 命令在与之前相同的目录中:

service.bat

例如,要启动 Elasticsearch,我们只需运行以下命令:

service.bat start

Manipulating data with the REST API


Elasticsearch 公开了一个非常丰富的 REST API,可用于搜索数据、索引数据和控制 Elasticsearch 行为。您可以想象使用 REST API 可以让您获取单个文档、索引或更新 文档、获取 Elasticsearch 当前状态的信息、创建或删除索引,或强制 Elasticsearch 移动索引的分片。当然,这些只是展示您对 Elasticsearch REST API 的期望的示例。现在,我们将专注于使用 create检索更新删除 Elasticsearch API (https://en.wikipedia.org/wiki/Create,_read,_update_and_delete),它允许我们使用 方式的 Elasticsearch 类似于我们使用任何其他 NoSQL 的方式(https://en.wikipedia.org/wiki/NoSQL) 数据存储。

Understanding the REST API

如果您从未使用过暴露 REST API 的 应用程序,您可能会惊讶于使用此类应用程序并记住如何使用它们是多么容易。在类似 REST 的架构中,每个请求都被定向到由地址中的路径指示的具体对象。例如,假设我们的假设应用程序公开 /books REST 端点作为对书籍列表的引用。在这种情况下,对 /books/1 的调用可能是对标识符为 1 的具体书籍的引用。您可以将其视为 API 的面向数据的模型.当然,我们可以嵌套路径——例如,像 /books/1/chapters 这样的路径可以返回标识符为 1 的书的章节列表和路径因为 /books/1/chapters/6 可能是对该书第六章的引用。

我们谈到了路径,但是当使用 HTTP 协议时,(https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol)我们有一些额外的动词(例如POSTGETPUT 等),除了路径之外,我们还可以使用它们来定义系统行为。因此,如果我们想检索标识符为 1 的书,我们将使用 GET 请求方法和 /books/1小路。但是,我们将使用具有相同路径的 PUT 请求方法来创建具有标识符的书籍记录,或者一个 POST更改记录的请求方法,DELETE 删除该条目,HEAD 请求方法获取有关所引用数据的基本信息由路径。

现在,让我们看一下发送到真实 Elasticsearch REST API 端点的 HTTP 请求示例,因此前面的假设信息将变成真实的:

GET http://localhost:9200/:这会检索有关 Elasticsearch 的基本信息,例如版本、命令发送到的节点名称、名称节点连接到的集群、Apache Lucene 版本等。

GET http://localhost:9200/_cluster/state/nodes/ 这会检索有关集群中所有节点的信息,例如它们的标识符、名称、带端口的传输地址、以及每个节点的附加节点属性。

DELETE http://localhost:9200/books/book/123:这会删除在书籍索引中编入索引的文档,书籍类型和标识符为 123。

我们现在知道 REST 意味着什么,我们可以开始专注于 Elasticsearch 来了解如何存储、检索、更改和删除索引中的数据。如果您想了解更多有关 REST 的信息,请参阅 http://en.wikipedia.org/wiki/Representational_state_transfer

Storing data in Elasticsearch

在 Elasticsearch 中,每个 文档都由三个属性表示——索引、类型和标识符。每个文档都必须被索引到一个单一索引中,需要其类型与文档结构相对应,并由标识符来描述。这三个属性允许我们识别 Elasticsearch 中的任何文档,并且需要在文档物理写入底层 Apache Lucene 索引时提供。有了这些知识,我们现在就可以创建我们的第一个 Elasticsearch 文档了。

Creating a new document

我们将通过索引一个文档开始学习 Elasticsearch REST API。假设我们正在构建一个 CMS 系统(http://en.wikipedia.org/ wiki/Content_management_system)将为我们的内部用户提供一个博客平台的功能。我们的索引中将有不同类型的文档,但最重要的是将发布并可供用户阅读的文章。

因为我们使用 JSON 表示法与 Elasticsearch 对话,而 Elasticsearch 再次使用 JSON 响应我们,所以我们的示例文档可能如下所示:

{ 
 "id": "1", 
 "title": "New version of Elasticsearch released!", 
 "content": "Version 2.2 released today!", 
 "priority": 10, 
 "tags": ["announce", "elasticsearch", "release"] 
}

正如您在前面的代码片段中看到的,JSON 文档是使用一组字段构建的,其中每个字段可以具有不同的格式。在我们的示例中,我们有一组文本字段(id、title 和 content)、一个数字(优先级字段)和一个文本值数组(标签字段)。我们将在接下来的示例中展示更复杂的文档。

Note

Elasticsearch 2.0 中引入的更改之一是字段名称不能包含点字符。这样的字段名称在旧版本的 Elasticsearch 中是可能的,但在某些情况下可能会导致序列化错误,因此 Elasticsearch 创建者决定消除这种可能性。

要记住的一件事是,默认情况下,Elasticsearch 用作无模式数据存储。这意味着它可以尝试猜测发送到 Elasticsearch 的文档中的字段类型。它将尝试将数字类型用于未包含在引号中的值和字符串用于包含在引号中的数据。它将尝试猜测日期并将它们索引到专用字段等中。这是可能的,因为 JSON 格式是半类型的。在内部,当第一个带有新字段的文档被发送到 Elasticsearch 时,它将被处理并写入映射(我们将在 Mappings 配置中详细讨论映射 第 2 章部分,索引您的数据< /跨度>)。

Note

当文档具有稍微不同的结构时,无模式方法和动态映射可能会出现问题——例如,第一个文档将包含不带引号的优先级字段的值(如所讨论的示例中所示),而第二个文档将为优先级字段中的值加上引号。这将导致错误,因为 Elasticsearch 会尝试将文本值放入数字字段中,而这在 Lucene 中是不可能的。因此,建议您定义自己的映射,您将在 映射配置 部分学习="#" linkend="ch02">第 2 章索引您的数据

现在让我们索引我们的文档并使其可用于检索和搜索。我们会将我们的文章索引到一个名为 blog 的索引,该索引的类型名为 article。我们还将给我们的文档一个标识符 1,因为这是我们的第一个文档。为了索引我们的示例文档,我们将执行以下命令:

curl -XPUT 'http://localhost:9200/blog/article/1' -d '{"title": "New version of Elasticsearch released!", "content": "Version 2.2 released today!", "priority": 10, "tags": ["announce", "elasticsearch", "release"] }'

请注意 curl 命令的一个新选项,即 -d 参数。此选项的值是将用作请求有效负载的文本 - 请求正文。这样,我们可以发送附加信息,例如文档定义。另请注意,唯一标识符位于 URL 中,而不是正文中。如果省略此标识符(在使用 HTTP PUT 请求时),索引请求将返回以下错误:

No handler found for uri [/blog/article] and method [PUT]

如果一切正常,Elasticsearch 将返回一个 JSON 响应,通知我们索引操作的状态。此响应应类似于以下响应:

{
 "_index":"blog",
 "_type":"article",
 "_id":"1",
 "_version":1,
 "_shards":{
  "total":2,
  "successful":1,
  "failed":0},
 "created":true
}

在前面的 响应中,Elasticsearch 包含有关操作状态、索引、类型、标识符和版本的信息。我们还可以看到有关参与操作的分片的信息——所有分片,成功的和失败的。

Automatic identifier creation

在前面的示例中,我们在将文档发送到 Elasticsearch 时手动指定了文档标识符。但是,有些用例是我们没有文档的标识符——例如,将日志作为我们的数据处理时。在这种情况下,我们希望某个应用程序为我们创建标识符,而 Elasticsearch 可以是这样的应用程序。当然,当您的文档已经拥有文档标识符(例如关系数据库中的数据)时,生成文档标识符是没有意义的。在这种情况下,您可能需要更新文件;在这种情况下,自动标识符生成不是最好的主意。但是,当我们需要这样的功能时,我们可以使用 POST 并省略标识符,而不是使用 HTTP PUT 方法在 REST API 路径中。因此,如果我们希望 Elasticsearch 在前面的示例中生成标识符,我们将发送如下命令:

curl -XPOST 'http://localhost:9200/blog/article/' -d '{"title": "New version of Elasticsearch released!", "content": "Version 2.2 released today!", "priority": 10, "tags": ["announce", "elasticsearch", "release"] }'

我们使用了 HTTP POST 方法而不是 PUT 并且我们省略了标识符。在这种情况下,Elasticsearch 产生的响应如下:

{
 "_index":"blog",
 "_type":"article",
 "_id":"AU1y-s6w2WzST_RhTvCJ",
 "_version":1,
 "_shards":{
  "total":2,
  "successful":1,
  "failed":0},
 "created":true
}

如您所见,Elasticsearch 返回的响应与前面的示例几乎相同,只是有一个 细微差别——_id 字段被返回。现在,我们的值不是 1 ,而是值 AU1y-s6w2WzST_RhTvCJ,这是 Elasticsearch 为我们的文档生成的标识符.

Retrieving documents

我们现在有两个文档被索引到我们的 Elasticsearch 实例中——一个使用显式标识符,一个 使用生成的标识符。现在让我们尝试使用其唯一标识符检索其中一个文档。为此,我们需要关于文档索引的索引、它的类型以及它具有的标识符的信息。例如,要从博客索引中获取文章类型和标识符为 1 的文档,我们将运行以下 HTTP GET 请求:

curl -XGET 'localhost:9200/blog/article/1?pretty'

Note

名为 pretty 的附加 URI 属性告诉 Elasticsearch 在响应中包含换行符和附加空格,以使输出更易于用户阅读。

Elasticsearch 将返回类似于以下内容的响应:

{
  "_index" : "blog",
  "_type" : "article",
  "_id" : "1",
  "_version" : 1,
  "found" : true,
  "_source" : {
    "title" : "New version of Elasticsearch released!",
    "content" : "Version 2.2 released today!",
    "priority" : 10,
    "tags" : [ "announce", "elasticsearch", "release" ]
  }
}

正如您在前面的响应中看到的那样,Elasticsearch 返回了 _source 字段,这是发送到 Elasticsearch 的原始文档以及一些告诉我们有关文档的附加字段,例如索引、类型、标识符、文档版本,当然还有关于是否找到文档的信息(找到的属性)。

如果我们尝试检索 索引中不存在的文档,例如具有 12345 标识符,我们得到这样的响应:

{
  "_index" : "blog",
  "_type" : "article",
  "_id" : "12345",
  "found" : false
}

可以看到,这次 found 属性的值被设置为 false 并且没有 _source 字段,因为尚未检索到文档。

Updating documents

与索引相比,在 索引中更新文档是一项更复杂的任务。当文档被编入索引并且 Elasticsearch 将文档刷新到 磁盘时,它会创建段——一个写入一次并多次读取的不可变结构。这样做是因为 Apache Lucene 创建的倒排索引目前无法更新(至少它的大部分部分)。为了更新文档,Elasticsearch 在内部首先使用 GET 请求获取文档,修改其 _source 字段,删除旧文档,并使用更新的内容索引新文档。内容更新是使用 Elasticsearch 中的脚本完成的(我们将在 Elasticsearch 的脚本功能 部分中详细讨论 Elasticsearch 中的脚本link" href="#" linkend="ch06">第 6 章让您的搜索更好)。

Note

请注意,以下文档更新示例要求您将 script.inline: on 属性放入您的 elasticsearch.yml 配置文件中.这是必需的,因为出于安全原因,Elasticsearch 中禁用了内联脚本。处理更新的另一种方法是将脚本内容存储在 Elasticsearch 配置目录中的文件中,但我们将在 Elasticsearch 的脚本功能中讨论第 6 章中的 span> 部分,让您的搜索更好

现在让我们尝试通过修改其 content 字段以包含 This is the updated document 语句来使用标识符 1 更新我们的文档。为此,我们需要使用 _update REST 端点在文档路径上运行 POST HTTP 请求。我们修改文档的请求如下所示:

curl -XPOST 'http://localhost:9200/blog/article/1/_update' -d '{ 
 "script" : "ctx._source.content = new_content",
 "params" : {
  "new_content" : "This is the updated document"
 }
}'

如您所见,我们已将请求发送到 /blog/article/1/_update REST 端点。在请求正文中,我们提供了两个参数 - script 属性中的更新脚本和 脚本的参数。脚本非常简单;它采用 _source 字段并通过将其值设置为 new_content 参数的值来修改内容字段。 params 属性包含所有脚本参数。

对于前面的 update 命令执行,Elasticsearch 会返回以下响应:

{"_index":"blog","_type":"article","_id":"1","_version":2,"_shards":{"total":2,"successful":1,"failed":0}}

在前面的响应中要查看的是 _version 字段。现在,版本是 2,这意味着文档已经更新(或重新索引)一次。基本上,每次更新都会使 Elasticsearch 更新 _version 字段。

我们还可以使用 doc 部分更新文档并提供更改的字段,例如:

curl -XPOST 'http://localhost:9200/blog/article/1/_update' -d '{
 "doc" : {
  "content" : "This is the updated document"
 }
}'

我们现在使用以下命令检索文档:

curl -XGET 'http://localhost:9200/blog/article/1?pretty'

我们从 Elasticsearch 得到以下响应:

{
  "_index" : "blog",
  "_type" : "article",
  "_id" : "1",
  "_version" : 2,
  "found" : true,
  "_source" : {
    "title" : "New version of Elasticsearch released!",
    "content" : "This is the updated document",
    "priority" : 10,
    "tags" : [ "announce", "elasticsearch", "release" ]
  }
}

如您所见,文档已正确更新。

Note

使用 Elasticsearch 的更新 API 时要记住的是,需要存在 _source 字段,因为这是 Elasticsearch 用来从索引中检索原始文档内容的字段。默认情况下,启用该字段 并且 Elasticsearch 使用它来存储原始文档。

Dealing with non-existing documents

涉及文档更新时的好处是,我们想提一下,因为它可以在使用 Elasticsearch Update API 时派上用场,我们可以定义当我们尝试更新的文档不存在时,Elasticsearch 应该做什么。

例如,让我们尝试增加标识符为 2 的不存在文档的优先级字段值:

curl -XPOST 'http://localhost:9200/blog/article/2/_update' -d '{ 
 "script" : "ctx._source.priority += 1"
}'

Elasticsearch 返回的响应或多或少如下所示:

{"error":{"root_cause":[{"type":"document_missing_exception","reason":"[article][2]: document missing","shard":"2","index":"blog"}],"type":"document_missing_exception","reason":"[article][2]: document missing","shard":"2","index":"blog"},"status":404}

可以想象,该文档没有更新,因为它不存在。所以现在,让我们修改我们的请求,在我们的请求正文中包含 upsert 部分,该部分将告诉 Elasticsearch 在文档不存在时要做什么。新命令如下所示:

curl -XPOST 'http://localhost:9200/blog/article/2/_update' -d '{ 
 "script" : "ctx._source.priority += 1",
 "upsert" : {
  "title" : "Empty document",
  "priority" : 0,
  "tags" : ["empty"]
 }
}'

使用修改后的请求,将索引一个新文档;如果我们使用 GET API 检索它,它将如下所示:

{
  "_index" : "blog",
  "_type" : "article",
  "_id" : "2",
  "_version" : 1,
  "found" : true,
  "_source" : {
    "title" : "Empty document",
    "priority" : 0,
    "tags" : [ "empty" ]
  }
}

如您所见,我们更新请求的 upsert 部分中的字段 已被 Elasticsearch 获取并使用作为文档字段。

Adding partial documents

除了我们已经写过关于更新API 的内容之外,Elasticsearch 还能够将更新请求中的部分文档合并到现有文档或使用索引新文档有关请求的信息,类似于我们在 upsert 部分看到的信息。

假设 我们想要更新我们的初始文档并添加一个名为 count 的新字段 strong>(最初设置为 1)。如果文档不存在,我们还想索引指定标识符下的文档。我们可以通过运行以下命令来做到这一点:

curl -XPOST 'http://localhost:9200/blog/article/1/_update' -d '{ 
  "doc" : {
    "count" : 1
  },
  "doc_as_upsert" : true
}

我们在 doc 部分中指定了新字段,并且我们说我们希望 doc 部分在以下情况下被视为 upsert 部分文档不存在(doc_as_upsert 属性设置为 true)。

如果我们现在检索该文档,我们会看到以下响应:

{
  "_index" : "blog",
  "_type" : "article",
  "_id" : "1",
  "_version" : 3,
  "found" : true,
  "_source" : {
    "title" : "New version of Elasticsearch released!",
    "content" : "This is the updated document",
    "priority" : 10,
    "tags" : [ "announce", "elasticsearch", "release" ],
    "count" : 1
  }
}

Note

有关 文档更新的完整参考,请参阅更新 API 上的 Elasticsearch 官方文档,该文档位于 https://www.elastic.co/guide/en/elasticsearch/reference /current/docs-update.html

Deleting documents

现在我们知道如何 对文档进行索引、更新和检索,是时候了解我们如何可以删除它们。从 Elasticsearch 索引中删除文档与检索文档非常相似,但有一个主要区别——我们必须使用 HTTP GET 方法文字">DELETE 一。

例如,如果我们想删除文章类型下的博客索引中索引为 1 的文档,我们将运行以下命令:

curl -XDELETE 'localhost:9200/blog/article/1'

Elasticsearch 的响应表明该文档已被删除,应该如下所示:

{
 "found":true,
 "_index":"blog",
 "_type":"article",
 "_id":"1",
 "_version":4,
 "_shards":{
  "total":2,
  "successful":1,
  "failed":0
 }
}

当然,在删除时,这 并不是唯一的。我们还可以删除给定类型的所有文档。例如,如果我们想删除整个博客索引,我们应该省略标识符和类型,所以命令看起来像这样:

curl -XDELETE 'localhost:9200/blog'

前面的命令将导致 blog 索引的删除。

Versioning

最后,当谈到 Elasticsearch 中的数据操作时,我们还想谈一谈——版本控制的伟大特性。您可能已经注意到,Elasticsearch 会在文档版本 更新时递增。我们可以利用此功能并使用乐观锁定 (http://en.wikipedia.org/ wiki/Optimistic_concurrency_control),并避免在多个进程或线程同时访问同一个文档时发生冲突和覆盖。您可以假设您的索引应用程序可能想要尝试更新文档,而用户想要在执行一些手动工作时更新文档。出现的问题是:哪个文档应该是正确的——由索引应用程序更新的文档,由用户更新的文档,还是更改的合并文档?如果更改发生冲突怎么办?为了处理这种情况,我们可以使用版本控制。

Usage example

让我们将一个新文档索引到我们的博客索引中——一个标识符为 10 的文档,并在我们这样做后不久为其第二个 版本建立索引。执行此操作的命令如下所示:

curl -XPUT 'localhost:9200/blog/article/10' -d '{"title":"Test document"}'
curl -XPUT 'localhost:9200/blog/article/10' -d '{"title":"Updated test document"}'

因为我们已经用相同的标识符索引了文档,所以它应该有一个版本 2(您可以使用 GET 请求检查它)。

现在,让我们尝试删除我们刚刚编制索引的文档,但让我们指定一个等于 1 的版本属性。通过这样做,我们告诉 Elasticsearch 我们有兴趣删除具有提供版本的文档。由于文档现在是不同的版本,Elasticsearch 不应该允许使用版本 1 进行索引。让我们检查一下我们所说的是否属实。我们将用来发送删除请求的命令如下所示:

curl -XDELETE 'localhost:9200/blog/article/10?version=1'

Elasticsearch 生成的响应应该类似于以下响应:

{
  "error" : {
    "root_cause" : [ {
      "type" : "version_conflict_engine_exception",
      "reason" : "[article][10]: version conflict, current [2], provided [1]",
      "shard" : 1,
      "index" : "blog"
    } ],
    "type" : "version_conflict_engine_exception",
    "reason" : "[article][10]: version conflict, current [2], provided [1]",
    "shard" : 1,
    "index" : "blog"
  },
  "status" : 409
}

如您所见,delete 操作不成功——版本不匹配。如果我们将 version 属性设置为 2,那么 delete 操作就会成功:

curl -XDELETE 'localhost:9200/blog/article/10?version=2&pretty'

这次的响应将如下所示:

{
  "found" : true,
  "_index" : "blog",
  "_type" : "article",
  "_id" : "10",
  "_version" : 3,
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  }
}

这次 delete 操作已经成功,因为提供的版本是正确的。

Versioning from external systems

Elasticsearch 版本控制功能的好处是我们可以提供我们希望 Elasticsearch 使用的文档版本。这使我们能够从作为我们主要数据存储的外部数据系统提供版本。为此,我们需要在索引期间提供一个附加参数——version_type=external,当然还有版本本身。例如,如果我们希望我们的文档具有 12345 版本,我们可以发送如下请求:

curl -XPUT 'localhost:9200/blog/article/20?version=12345&version_type=external' -d '{"title":"Test document"}'

Elasticsearch 返回的响应如下:

{
  "_index" : "blog",
  "_type" : "article",
  "_id" : "20",
  "_version" : 12345,
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "created" : true
}

我们只需要记住,在使用 version_type=external 时,我们需要在索引文档的情况下提供版本。在我们想要更改文档并使用乐观锁定的情况下,我们需要提供等于或高于文档中存在的版本的版本参数。

Searching with the URI request query


在进入 Elasticsearch 查询语言的美妙世界之前,我们想向您介绍 简单但非常灵活的 URI 请求搜索,它允许我们使用一个简单的 Elasticsearch 查询与 Lucene 查询语言相结合。当然,我们将在第 3 章搜索你的数据,但现在我们将坚持最简单的方法。

Sample data

出于本书部分的目的,我们将创建一个包含两种文档类型的简单索引。为此,我们将运行以下六个命令:

curl -XPOST 'localhost:9200/books/es/1' -d '{"title":"Elasticsearch Server", "published": 2013}'
curl -XPOST 'localhost:9200/books/es/2' -d '{"title":"Elasticsearch Server Second Edition", "published": 2014}'
curl -XPOST 'localhost:9200/books/es/3' -d '{"title":"Mastering Elasticsearch", "published": 2013}'
curl -XPOST 'localhost:9200/books/es/4' -d '{"title":"Mastering Elasticsearch Second Edition", "published": 2015}'
curl -XPOST 'localhost:9200/books/solr/1' -d '{"title":"Apache Solr 4 Cookbook", "published": 2012}'
curl -XPOST 'localhost:9200/books/solr/2' -d '{"title":"Solr Cookbook Third Edition", "published": 2015}'

运行上述命令将创建具有两种类型的图书索引:essolr。标题和已发布字段将被编入索引,因此可搜索。

URI search

Elasticsearch 中的所有查询都发送到 _search 端点。您可以搜索单个索引或多个索引,并且可以将搜索限制为给定的文档类型或 多种类型。例如,为了搜索我们图书的索引,我们将运行以下命令:

curl -XGET 'localhost:9200/books/_search?pretty'

Elasticsearch 返回的结果将包括我们图书索引中的所有文档(因为没有指定查询)并且应该类似于以下内容:

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 6,
    "max_score" : 1.0,
    "hits" : [ {
      "_index" : "books",
      "_type" : "es",
      "_id" : "2",
      "_score" : 1.0,
      "_source" : {
        "title" : "Elasticsearch Server Second Edition",
        "published" : 2014
      }
    }, {
      "_index" : "books",
      "_type" : "es",
      "_id" : "4",
      "_score" : 1.0,
      "_source" : {
        "title" : "Mastering Elasticsearch Second Edition",
        "published" : 2015
      }
    }, {
      "_index" : "books",
      "_type" : "solr",
      "_id" : "2",
      "_score" : 1.0,
      "_source" : {
        "title" : "Solr Cookbook Third Edition",
        "published" : 2015
      }
    }, {
      "_index" : "books",
      "_type" : "es",
      "_id" : "1",
      "_score" : 1.0,
      "_source" : {
        "title" : "Elasticsearch Server",
        "published" : 2013
      }
    }, {
      "_index" : "books",
      "_type" : "solr",
      "_id" : "1",
      "_score" : 1.0,
      "_source" : {
        "title" : "Apache Solr 4 Cookbook",
        "published" : 2012
      }
    }, {
      "_index" : "books",
      "_type" : "es",
      "_id" : "3",
      "_score" : 1.0,
      "_source" : {
        "title" : "Mastering Elasticsearch",
        "published" : 2013
      }
    } ]
  }
}

如您所见,响应有一个标头,告诉您查询的总时间和查询过程中使用的分片。除此之外,我们还有与查询匹配的文档——默认情况下前 10 个 文档。每个文档都由索引、类型、标识符、分数和文档的来源来描述,即发送到 Elasticsearch 的原始文档。

我们还可以针对许多索引运行查询。例如,如果我们有另一个名为 clients 的索引,我们还可以对这两个索引运行单个查询,如下所示:

curl -XGET 'localhost:9200/books,clients/_search?pretty'

我们还可以通过完全省略索引名称或将查询设置为 _all

curl -XGET 'localhost:9200/_search?pretty'
curl -XGET 'localhost:9200/_all/_search?pretty'

以类似的方式,我们也可以在搜索过程中选择我们想要使用的类型。例如,如果我们只想在书的索引中搜索 es 类型,我们运行如下命令:

curl -XGET 'localhost:9200/books/es/_search?pretty' 

请记住,为了搜索给定的类型,我们需要指定索引或多个索引。在选择索引名称时,Elasticsearch 允许我们拥有相当丰富的语义。如果您有兴趣,请参考 https://www.elastic.co/guide/en/elasticsearch/reference/current/multi-index.html;但是,我们想指出一件事。在针对多个索引运行查询时,可能会发生其中一些不存在或已关闭的情况。在这种情况下,ignore_unavailable 属性就派上用场了。当设置为 true 时,它告诉 Elasticsearch 忽略不可用或关闭的索引。

例如,让我们尝试 运行以下查询:

curl -XGET 'localhost:9200/books,non_existing/_search?pretty' 

响应 将类似于以下响应:

{
  "error" : {
    "root_cause" : [ {
      "type" : "index_missing_exception",
      "reason" : "no such index",
      "index" : "non_existing"
    } ],
    "type" : "index_missing_exception",
    "reason" : "no such index",
    "index" : "non_existing"
  },
  "status" : 404
}

现在让我们检查如果我们将 ignore_unavailable=true 添加到我们的请求并执行以下命令会发生什么:

curl -XGET 'localhost:9200/books,non_existing/_search?pretty&ignore_unavailable=true'

在这种情况下,Elasticsearch 将返回结果而不会出现任何错误。

Elasticsearch query response

假设我们 想要在我们的书的索引中查找所有包含 elasticsearch 术语的文档标题字段。我们可以通过运行以下查询来做到这一点:

curl -XGET 'localhost:9200/books/_search?pretty&q=title:elasticsearch'

Elasticsearch 对上述请求返回的响应如下:

{
  "took" : 37,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 4,
    "max_score" : 0.625,
    "hits" : [ {
      "_index" : "books",
      "_type" : "es",
      "_id" : "1",
      "_score" : 0.625,
      "_source" : {
        "title" : "Elasticsearch Server",
        "published" : 2013
      }
    }, {
      "_index" : "books",
      "_type" : "es",
      "_id" : "2",
      "_score" : 0.5,
      "_source" : {
        "title" : "Elasticsearch Server Second Edition",
        "published" : 2014
      }
    }, {
      "_index" : "books",
      "_type" : "es",
      "_id" : "4",
      "_score" : 0.5,
      "_source" : {
        "title" : "Mastering Elasticsearch Second Edition",
        "published" : 2015
      }
    }, {
      "_index" : "books",
      "_type" : "es",
      "_id" : "3",
      "_score" : 0.19178301,
      "_source" : {
        "title" : "Mastering Elasticsearch",
        "published" : 2013
      }
    } ]
  }
}

响应的第一部分为我们提供了有关请求花费了多少时间的信息(took 属性以毫秒为单位指定),是否超时(timed_out 属性),以及请求执行期间查询的分片信息——查询的分片数(_shards 对象的总属性) ,成功返回结果的分片数(_shards对象的success属性),失败的分片数(_shards 对象)。如果执行的时间比我们想要的长,查询也可能会超时。 (我们 可以使用 timeout 参数指定最大查询执行时间。)失败的分片意味着该分片出现问题或在执行期间不可用搜索执行。

当然,上面提到的信息可能很有用,但通常我们对 hits 对象中返回的结果感兴趣。我们有查询返回的文档总数(在 total 属性中)和计算的最大分数(在 max_score财产)。最后,我们有 hits 数组,其中包含返回的文档。在我们的例子中,每个返回的文档都包含它的索引名称(_index 属性)、类型(_type 属性)、标识符(_id 属性)、分数(_score 属性)和 _source 字段(通常,这是为索引而发送的 JSON 对象。

Query analysis

您可能想知道为什么我们在上一节中运行的查询有效。我们对 Elasticsearch 术语进行了索引,并对 Elasticsearch 进行了查询,尽管它们不同(大写),但还是找到了相关文档。原因在于分析。在索引期间,底层 Lucene 库会根据 Elasticsearch 配置分析文档并索引数据。默认情况下,Elasticsearch 会告诉 Lucene 索引 并分析基于字符串的数据和数字。在查询过程中也会发生同样的情况,因为 URI 请求查询映射到 query_string 查询(将在 第 3 章搜索您的数据),该查询由 Elasticsearch 分析。

让我们使用索引分析 API ( https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-analyze.html)。它允许 我们查看分析过程是如何完成的。有了这个,我们可以看到在索引过程中一个文档发生了什么,以及在查询过程中我们的查询短语发生了什么。

为了查看在 Elasticsearch 服务器短语的标题字段中索引的内容,我们将运行以下命令:

curl -XGET 'localhost:9200/books/_analyze?pretty&field=title' -d 'Elasticsearch Server'

响应如下:

{
  "tokens" : [ {
    "token" : "elasticsearch",
    "start_offset" : 0,
    "end_offset" : 13,
    "type" : "<ALPHANUM>",
    "position" : 0
  }, {
    "token" : "server",
    "start_offset" : 14,
    "end_offset" : 20,
    "type" : "<ALPHANUM>",
    "position" : 1
  } ]
}

可以看到,Elasticsearch 将文本分成了两个词条——第一个词的标记值为 elasticsearch,第二个词的标记值为服务器。

现在让我们看看 是如何分析查询文本的。我们可以通过运行以下命令来做到这一点:

curl -XGET 'localhost:9200/books/_analyze?pretty&field=title' -d 'elasticsearch'

请求的响应如下所示:

{
  "tokens" : [ {
    "token" : "elasticsearch",
    "start_offset" : 0,
    "end_offset" : 13,
    "type" : "<ALPHANUM>",
    "position" : 0
  } ]
}

我们可以看到这个词与我们传递给查询的原始词相同。 Lucene的查询细节和查询解析器是如何构造查询的我们就不赘述了,但总的来说分析后的索引词与分析后的查询中的索引词是一样的;因此,文档匹配查询并返回结果。

URI query string parameters

我们可以使用一些参数来控制URI查询行为,我们将讨论这些< /a> 现在。要记住的是,查询中的每个参数都应该与 & 字符连接,如下例所示:

curl -XGET 'localhost:9200/books/_search?pretty&q=published:2013&df=title&explain=true&default_operator=AND'

请记住 使用 ' 字符将请求的 URL 括起来,因为在基于 Linux 的系统上, & 字符将被 Linux shell 分析。

The query

q 参数允许 我们指定我们希望文档匹配的查询。它允许我们使用本章后面的 Lucene 查询语法 部分中描述的 Lucene 查询语法来指定查询。例如,一个简单的查询如下所示:q=title:elasticsearch

The default search field

使用 df 参数,我们可以指定在没有字段指示符为 时应该使用的默认搜索字段q 参数中使用。默认情况下,将使用 _all 字段。 (这是 Elasticsearch 用来复制所有其他字段内容的字段。我们将在 第 2 章中更深入地讨论这个问题, 索引您的数据)。 df 参数值的示例可以是 df=title

Analyzer

analyzer 属性允许我们定义用于分析查询的分析器的名称。 默认情况下,我们的查询将由在索引期间用于分析字段内容的同一分析器进行分析。

The default operator property

default_operator 属性可以设置为 ORAND,允许我们指定用于我们查询的默认布尔运算符 (http://en.wikipedia.org/wiki/Boolean_algebra)。默认情况下,它设置为 OR,这意味着单个查询词匹配足以返回文档。将此参数设置为查询的 AND 将导致返回与所有查询词匹配的文档。

Query explanation

如果我们将 explain 参数设置为 true,Elasticsearch 将在每个 explain 信息"indexterm">结果中的文档——例如从中获取文档的分片以及有关评分计算的详细信息(我们将在 理解第6章中的解释信息部分,让您的搜索更好)。还要记住不要在正常搜索查询期间获取解释信息,因为它需要额外的资源并增加查询的性能下降。例如,包含解释信息的查询可能如下所示:

curl -XGET 'localhost:9200/books/_search?pretty&explain=true&q=title:solr'

Elasticsearch 为上述查询返回的结果 如下:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.70273256,
    "hits" : [ {
      "_shard" : 2,
      "_node" : "v5iRsht9SOWVzu-GY-YHlA",
      "_index" : "books",
      "_type" : "solr",
      "_id" : "2",
      "_score" : 0.70273256,
      "_source" : {
        "title" : "Solr Cookbook Third Edition",
        "published" : 2015
      },
      "_explanation" : {
        "value" : 0.70273256,
        "description" : "weight(title:solr in 0) [PerFieldSimilarity], result of:",
        "details" : [ {
          "value" : 0.70273256,
          "description" : "fieldWeight in 0, product of:",
          "details" : [ {
            "value" : 1.0,
            "description" : "tf(freq=1.0), with freq of:",
            "details" : [ {
              "value" : 1.0,
              "description" : "termFreq=1.0",
              "details" : [ ]
            } ]
          }, {
            "value" : 1.4054651,
            "description" : "idf(docFreq=1, maxDocs=3)",
            "details" : [ ]
          }, {
            "value" : 0.5,
            "description" : "fieldNorm(doc=0)",
            "details" : [ ]
          } ]
        } ]
      }
    }, {
      "_shard" : 3,
      "_node" : "v5iRsht9SOWVzu-GY-YHlA",
      "_index" : "books",
      "_type" : "solr",
      "_id" : "1",
      "_score" : 0.5,
      "_source" : {
        "title" : "Apache Solr 4 Cookbook",
        "published" : 2012
      },
      "_explanation" : {
        "value" : 0.5,
        "description" : "weight(title:solr in 1) [PerFieldSimilarity], result of:",
        "details" : [ {
          "value" : 0.5,
          "description" : "fieldWeight in 1, product of:",
          "details" : [ {
            "value" : 1.0,
            "description" : "tf(freq=1.0), with freq of:",
            "details" : [ {
              "value" : 1.0,
              "description" : "termFreq=1.0",
              "details" : [ ]
            } ]
          }, {
            "value" : 1.0,
            "description" : "idf(docFreq=1, maxDocs=2)",
            "details" : [ ]
          }, {
            "value" : 0.5,
            "description" : "fieldNorm(doc=1)",
            "details" : [ ]
          } ]
        } ]
      }
    } ]
  }
}

The fields returned

默认情况下,对于返回的每个文档,Elasticsearch 将包含 index 名称、type 名称、document 标识符、score_source 字段。我们可以通过添加 fields 参数并指定以逗号分隔的字段名称列表来修改此行为。字段 将从存储的字段中检索(如果存在;我们将在 第 2 章索引您的数据)或来自内部_source 场。默认情况下,fields 参数的值为 _source。例如:fields=title,priority

我们还可以通过添加 _source 参数并将其值设置为

Sorting the results

使用 sort 参数,我们可以指定自定义排序。 Elasticsearch 的默认行为是按照 _score 字段值的降序对返回的文档进行排序。如果我们想对文档进行不同的排序,我们需要指定 sort 参数。例如,添加 sort=published:desc 将按照已发布字段的降序对文档进行排序。通过添加 sort=published:asc 参数,我们将告诉 Elasticsearch 根据已发布字段升序对文档进行排序。

如果我们指定自定义排序,Elasticsearch 将省略文档的 _score 字段计算。在您的情况下,这可能不是所需的行为。如果您希望在使用自定义排序时仍跟踪每个文档的分数,则应将 track_scores=true 属性添加到您的查询中。请注意,由于计算分数所需的处理能力,在进行自定义排序时跟踪分数会使查询变慢(您甚至可能没有注意到差异)。

The search timeout

默认情况下,Elasticsearch 没有查询超时,但您可能希望查询在 一定时间(例如 5 秒)后超时. Elasticsearch 允许您通过公开超时参数来做到这一点。当指定超时参数时,查询将执行到给定的超时值,并且将返回到该点收集的结果。要指定 5 秒的超时,您必须将 timeout=5s 参数添加到您的 查询.

The results window

Elasticsearch 允许您指定结果窗口(结果列表中应该返回 的文档范围)。我们有两个参数允许我们指定结果窗口大小:sizefrom。 size 参数默认为 10,并定义返回的最大结果数。 from 参数默认为 0,并指定应从哪个文档返回结果。为了返回从第 11 个开始的五个文档,我们将在查询中添加以下参数:size=5&from=10

Limiting per-shard results

Elasticsearch 允许 我们使用 terminate_after 属性和指定最大文档数。例如,如果我们想从每个分片中获取不超过 100 个文档,我们可以将 terminate_after=100 添加到我们的 URI 请求中。

Ignoring unavailable indices

当对多个索引运行 查询时,告诉 Elasticsearch 我们不关心不可用的索引是很方便的。默认情况下,如果其中一个索引不可用,Elasticsearch 将抛出错误,但我们可以通过简单地将 ignore_unavailable=true 参数添加到我们的 URI 请求来更改这一点。

The search type

URI 查询 允许我们使用 search_type 参数指定搜索类型,默认为 query_then_fetch。我们可以在这里使用的两个值是:dfs_query_then_fetchquery_then_fetch。旧 Elasticsearch 版本中可用的其余搜索类型现已弃用或删除。我们将在 了解查询过程 部分了解有关搜索类型的更多信息ch03">第 3 章搜索您的数据

Wildcard and prefix analysis

默认情况下,不分析 通配符查询和前缀查询。如果我们想改变这种行为,我们可以设置analyze_wildcard属性true

Note

如果您想查看 Elasticsearch 公开的所有参数作为 URI 请求参数,请 参考官方文档:https://www.elastic.co/guide/en /elasticsearch/reference/current/search-uri-request.html

Lucene query syntax

我们认为最好多了解一下在 URI 查询中传递的 q 参数中可以使用什么语法。 Elasticsearch 中的一些查询(例如当前正在讨论的查询)支持 Lucene 查询解析器语法——允许 您构建查询的语言。让我们看一下它并讨论一些基本功能。

我们传递给 Lucene 的查询被查询解析​​器分为术语和运算符。让我们从条款开始;您可以将它们区分为两种类型——单个术语和短语。例如,要在 title 字段中查询 book 术语,我们将传递以下查询:

title:book

要在标题字段中查询 elasticsearch book 短语,我们将通过以下查询:

title:"elasticsearch book"

您可能已经注意到开头的字段名称以及后面的术语或短语。

正如我们已经说过的,Lucene 查询语法支持运算符。例如,+ 运算符告诉 Lucene 给定的部分必须在文档中匹配,这意味着我们要搜索的词必须出现在文档的字段中。 - 操作符正好相反,这意味着查询的这一部分不能出现在文档中。没有 +- 运算符的查询部分将被视为可以匹配但查询的给定部分这不是强制性的。因此,如果我们想在标题字段中查找具有 book 术语而在描述字段中没有 cat 术语的文档,我们发送以下查询:

+title:book -description:cat

我们还可以用括号对多个术语进行分组,如以下查询所示:

title:(crime punishment)

我们还可以使用^ 运算符及其后的 boost 值,如以下查询所示:

title:book^4

这些是 Lucene 查询语言的基础知识,应该允许您毫无问题地使用 Elasticsearch 和构造查询。但是,如果您对 Lucene 查询语法感兴趣并想深入探索,请参阅查询解析器的官方文档 ,网址为http: //lucene.apache.org/core/5_4_0/queryparser/org/apache/lucene/queryparser/classic/package-summary.html

Summary


在本章中,我们了解了全文搜索是什么以及 Apache Lucene 对此的贡献。除此之外,我们现在已经熟悉了 Elasticsearch 的基本概念及其顶层架构。我们使用 Elasticsearch REST API 不仅可以索引数据,还可以更新、检索并最终删除数据。我们已经了解了版本控制是什么以及如何在 Elasticsearch 中使用它进行乐观锁定。最后,我们使用简单的 URI 查询来搜索我们的数据。

在下一章中,我们将专注于索引我们的数据。我们将了解 Elasticsearch 索引的工作原理以及主分片和副本的作用。我们将看到 Elasticsearch 如何处理它不知道的数据,以及如何创建我们自己的映射——描述索引结构的 JSON 结构。我们还将学习如何使用批量索引来加快索引过程,以及可以与索引一起存储哪些附加信息来帮助我们实现目标。此外,我们将讨论什么是索引段、什么是段合并以及如何调整段。最后,我们将了解路由在 Elasticsearch 中的工作原理,以及在索引和查询路由方面我们有哪些选择。