《深入理解Elasticsearch(原书第2版)》一第1章Elasticsearch简介1.1 Apache Lucene简介

第1章

Elasticsearch简介

我们希望读者通过阅读本书来获取和拓展关于Elasticsearch的基本知识。假设读者已经知道如何使用Elasticsearch进行单次或批量索引创建,如何发送请求检索感兴趣的文档,如何使用过滤器缩减检索返回文档的数量,以及使用切面/聚合(faceting/aggregation)机制来计算数据的一些统计量。不过,在接触Elasticsearch提供的各种令人激动的功能之前,希望读者能对Apache Lucene有一个快速的了解,因为Elasticsearch使用开源全文检索库Lucene进行索引和搜索。此外,我们还希望读者能了解Elasticsearch的一些基础概念。为了加速我们的学习,需要牢记这些基础知识,当然,这并不难掌握。同时,我们也需要确保读者能按Elasticsearch所需要的那样正确地理解Lucene。到本章结束为止,将涵盖以下内容:
Apache Lucene是什么
Lucene的整体架构
文本分析过程是如何实现的
Apache Lucene的查询语言及其使用
Elasticsearch的基本概念
Elasticsearch内部是如何通信的

1.1 Apache Lucene简介

为了全面理解Elasticsearch的工作原理,尤其是索引和查询处理环节,对Apache Lucene的理解显得至关重要。揭开Elasticsearch神秘的面纱,你会发现它在内部使用Apache Lucene创建索引,同时也使用Apache Lucene进行搜索。在接下来的几页里,将向读者展示Apache Lucene的基本概念,特别是那些从来没有使用过Lucene的读者们。

1.1.1 熟悉Lucene

读者也许会好奇,为什么Elasticsearch的创始人决定使用Apache Lucene而不是开发一个自己的全文检索库。对于这个问题,笔者并不是很确定,毕竟我们不是这个项目的创始人,我们猜想是因为Lucene的以下特点而得到了创始人的青睐:成熟,高性能,可扩展,轻量级以及强大的功能。Lucene内核可以创建为单个Java库文件,并且不依赖第三方代码,用户可以使用它提供的各种所见即所得的全文检索功能进行索引和搜索操作。当然,Lucene还有很多扩展,它们提供了各种各样的功能,例如多语言处理、拼写检查、高亮显示等。如果不需要这些额外的特性,可以下载单个的Lucene core库文件,直接在应用程序中使用它。

1.1.2 Lucene的总体架构

尽管我们可以直接探讨Apache Lucene架构的细节,但是有些概念还是需要提前了解的,以便于更好地理解Lucene的架构,它们包括:
文档(document):索引与搜索的主要数据载体,它包含一个或多个字段,存放将要写入索引的或将从索引搜索出来的数据。
字段(field):文档的一个片段,它包括字段的名称和字段的内容两个部分。
词项(term):搜索时的一个单位,代表了文本中的一个词。
词条(token):词项在字段文本中的一次出现,包括词项的文本、开始和结束的偏移以及词条类型。
Apache Lucene将写入索引的所有信息组织为倒排索引(inverted index)的结构形式。倒排索引是一种将词项映射到文档的数据结构,它与传统的关系数据库的工作方式不同。你可以认为倒排索引是面向词项的而不是面向文档的。我们来看看简单的倒排索引是什么样的。例如,假设我们有一些只包含title字段的文档,如下所示:
Elasticsearch Server(文档1)
Mastering Elasticsearch(文档2)
Apache Solr 4 Cookbook(文档3)
这些文档索引好以后,可简略地显示如下图:

正如你所见,每个词项指向该词项所出现过的文档数。这种索引组织方式允许快速有效的搜索操作,例如基于词项的查询。除了词项本身以外,每个词项有一个与之关联的计数(即文档频率),该计数可以告诉Lucene这个词项在多少个文档中出现过。
每个索引由多个段(segment)组成,每个段写入一次但是查询多次。索引期间,一个段创建以后不再修改。例如,文档被删除以后,删除信息单独保存在一个文件中,而段本身并没有被修改。
多个段将会在段合并(segments merge)阶段被合并在一起。或者强制执行段合并,或者由Lucene的内在机制决定在某个时刻执行段合并,合并后段的数量更少,但是更大。段合并非常耗费I/O,合并期间有些不再使用的信息将被清理掉,例如,被删除的文档。对于容纳相同数据的索引,段的数量更少的时候搜索速度更快。尽管如此,还是需要强调一下:因为段合并非常耗费I/O,请不要强制进行段合并,你只需要仔细配置段合并策略,剩余的事情Lucene会自行完成。
 
当然,实际的Lucene索引比前面提到的更复杂、更高深,除了词项的文档频率和出现该词项的文档列表外,还包含其他附加信息。在这里我们会介绍一些索引中的附加信息。了解这些信息对我们很有帮助,尽管它们只在Lucene内部使用。
(1)norm
norm是一种与每个被索引文档相关的因子,它存储文档的归一化结果,被用于计算查询的相关得分。norm基于索引时的文档加权值(boost)计算得出,与文档一起被索引存储。使用norm可以让Lucene在建立索引时考虑不同文档的权重,不过需要一些额外的磁盘空间和内存来索引和存储norm信息。
(2)词项向量
词项向量(term vector)是一种针对每个文档的微型倒排索引。词项向量的每个维由词项和出现频率结对组成,还可以包括词项的位置信息。Lucene和Elasticsearch默认都禁用词项向量索引,不过要实现某些功能,如关键词高亮等需要启用这个选项。
(3)倒排项格式
随着Lucene 4.0的发布,Lucene引入了解码器架构,允许开发者控制索引文件写入磁盘的格式,倒排项就是索引中可定制的部分之一。倒排项中可以存储字段、词项、文档、词项位置和偏移以及载荷(payload,一个在Lucene索引中随意存放的字节数组,可以包含任何我们需要的信息)。针对不同的使用目的,Lucene提供了不同的倒排项格式。比如,有一种优化后的格式是专门为高散列范围字段如唯一标识提供的。
(4)doc values
我们前面提到过,Lucene索引是一种倒排索引。不过,针对某些功能,如切面(faceting)或聚合(aggregation),这种倒排索引架构就不是最佳选择。这类功能通常需要操作文档而不是词项,Lucene需要把索引翻转过来构成正排索引才能完成这些功能所需要的计算。基于这些考虑,Lucene引入了doc values和额外的数据结构来进行分组、排序和聚合。doc values存储字段的正排索引。Lucene和Elasticsearch都允许我们通过配置来指定doc values的存储实现方式。可选的存储实现包括基于内存的、基于硬盘的,以及二者的混合。

1.1.3 分析数据

读者也许会好奇,文档中的数据是如何转化为倒排索引的?查询串又是怎么转换为可以用于搜索的词项的?这个转换过程被称为分析(analysis)。
文本分析由分析器来执行,它建立在分词器(tokenizer)、过滤器(filter)及字符映射器(character mapper)之上。
Lucene的分词器用来将文本切割成词条,词条是携带各种额外信息的词项,这些信息包括:词项在原始文本中的位置,词项的长度。分词器工作的结果被称为词条流,因为这些词条被一个接一个地推送给过滤器处理。
除了分词器,过滤器也是Lucene分析器的组成部分。过滤器数额可选,可以为零个、一个或多个,用于处理词条流中的词条。例如,它可以移除、修改词条流中的词条,甚至可以创造新的词条。Lucene中有很多现成的过滤器,你也可以根据需要实现新的过滤器。以下是一些过滤器的例子。
小写过滤器:将所有词条转化为小写。
ASCII过滤器:移除词条中所有非ASCII字符。
同义词过滤器:根据同义词规则,将一个词条转化为另一个词条。
多语言词干还原过滤器:将词条的文本部分归约到它们的词根形式,即词干还原。当分析器中有多个过滤器时,会逐个处理,理论上可以有无限多个过滤器。
过滤器可以一个接一个地被调用,因此我们可以通过逐个添加多个过滤器的方式来获得近乎无限的分析能力。
最后我们介绍字符映射器,它用于调用分词器之前的文本预处理操作。字符映射器的一个例子就是HTML文本的去标签处理。
索引与查询
也许读者会好奇,Lucene以及所有基于Lucene的软件是如何控制索引及查询操作的?在索引期,Lucene会使用你选择的分析器来处理文档中的内容,可以对不同的字段使用不同的分析器,例如,文档的title字段与description字段就可以使用不同的分析器。
在检索时,如果你使用了某个查询分析器(query parser),那么你的查询串将会被分析。当然,你也可以选择不分析数据。有一点需要牢记,Elasticsearch中有些查询会被分析,而有些则不会被分析。例如,前缀查询(prefix query)不会被分析,而匹配查询(match query)会被分析。
你还应该记住,索引期与检索期的文本分析要采用同样的分析器,只有查询(query)分词出来的词项与索引中词项能匹配上,才会返回预期的文档集。例如,如果在索引期使用了词干还原与小写转换,那么在查询期,也应该对查询串做相同的处理,否则,查询可能不会返回任何结果。

1.1.4 Lucene查询语言

Elasticsearch提供的一些查询类型(query type)支持Apache Lucene的查询解析语法,因此,我们应该深入了解Lucene的查询语言。
1. 理解基本概念
在Lucene中,一个查询(query)通常被分割为词项与操作符。Lucene中的词项可以是单个的词,也可以是一个短语(用双引号括起来的一组词)。如果查询被设置为要被分析,那么预先选定的分析器将会对查询中的所有词项进行处理。
一个查询也可以包含布尔操作符。布尔操作符连接多个词项,使之构成从句(clause)。有以下这些布尔操作符。
AND:它的含义是,文档匹配当前从句当且仅当AND操作符左右两边的词项都在文档中出现。例如,我们想执行“apache AND lucene”这样的查询,只有同时包含“apache”和“lucene”这两个词项的文档才会被返回给用户。
OR:它的含义是,包含当前从句中任意词项的文档都被视为与该从句匹配。例如,我们执行“apache OR lucene”这样的查询,任意包含词项“apache”或词项“lucene”的文档都会返回给用户。
NOT:它的含义是,与当前从句匹配的文档必须不包含NOT操作符后面的词项。例如,我们执行“lucene NOT elasticsearch”这样的查询,只有包含词项“lucene”且不包含词项“elasticsearch”的文档才会被返回给用户。
除了前面介绍的那些操作符以外,我们还可以使用以下这些操作符。
+:它的含义是,只有包含了“+”操作符后面词项的文档才会被认为与从句匹配。例如,我们想查找那些必须包含“lucene”但是“apache”可出现可不出现的文档,可执行如下查询:“+lucene apache”。
–:它的含义是,与从句匹配的文档,不能出现“-”操作符后的词项。例如,我们想查找那些包含了“lucene”但是不包含“Elasticsearch”的文档,可以执行如下查询:“+lucene -elasticsearch”。
如果查询中没有出现前面提到过的任意操作符,那么默认使用OR操作符。
除了前面介绍的内容之外,有一件事情值得一提:可以使用圆括号对从句进行分组,以构造更复杂的从句,例如:

  1. 在字段中查询
    就像Elasticsearch的处理方式那样,Lucene中所有数据都存储在字段(field)中,而字段又是文档的组成单位。为了实现针对某个字段的查询,用户需要提供字段名称,再加上冒号以及将要在该字段中执行查询的从句。如果你想查询所有在“title”字段中包含词项“Elasticsearch”的文档,可执行以下查询:

也可以在一个字段中同时使用多个从句,例如,如果你想查找所有在“title”字段中同时包含词项“Elasticsearch”和短语“mastering book”的文档,可执行如下查询:

当然,上面的查询也可以写成下面这种形式:

  1. 词项修饰符
    除了使用简单词项和从句的常规字段查询以外,Lucene允许用户使用修饰符(modifier)修改传入查询对象的词项。毫无疑问,最常见的修饰符就是通配符(wildcard)。Lucene支持两种通配符:?和*。前者匹配任意一个字符,而后者匹配多个字符。
     请记住,出于对性能的考虑,通配符不能作为词项的第一个字符出现。
    除通配符之外,Lucene还支持模糊(fuzzy and proximity)查询,办法是使用“~”字符以及一个紧随其后的整数值。当使用该修饰符修饰一个词项时,意味着我们想搜索那些包含该词项近似词项的文档(所以这种查询称为模糊查询)。~字符后的整数值确定了近似词项与原始词项的最大编辑距离。例如,当我们执行查询writer~2,意味着包含词项writer和writers的文档都可以被视为与查询匹配。
    当修饰符~用于短语时,其后的整数值用于告诉Lucene词项之间多大距离是可以接受的。例如,我们执行如下查询:

在title字段中包含mastering Elasticsearch的文档被视为与查询匹配,而包含mastering book Elasticsearch的文档则被认为不匹配。而如果我们执行下面这个查询:

则这两个文档都被认为与查询匹配。
此外,还可以使用^字符并赋以一个浮点数对词项加权(boosting),从而提高该词项的重要程度。如果都被加权,则权重值较大的词项更重要。默认情况下词项权重为1。可以参考2.1节进一步了解什么是权重值(boost value),以及其在文档评分中的作用。
我们也可以使用方括号和花括号来构建范围查询。例如,我们想在一个数值类型的字段上执行一个范围查询,执行如下查询即可:

上面查询的返回文档的price字段的值大于等于10.00并小于等于15.00。
当然,我们也可以在字符串类型的字段上执行范围查询(range query),例如:name:[Adam TO Adria]
上面查询的返回文档的name字段中,包含了按字典顺序介于Adam 和Adria之间(包括Adam和Adria)的词项。
如果想执行范围查询同时又想排除边界值,则可使用花括号作为修饰符。例如,我们想查找price字段值大于等于10.00但小于15.00的文档,可使用如下查询:

如果想执行一边受限而另一边不做限制的范围查询,例如,查找price字段值大于等于10.00的文档,可使用如下查询:

  1. 特殊字符处理
    很多应用场景中,也许你想搜索某个特殊字符(这些特殊字符包括+、–、&&、||、!、(,)、{}、[]、^、"、~、*、?、:、\、/),需要先使用反斜杠对这些特殊字符进行转义。例如,你可能想搜索abc"efg这个词项,需要按如下方式处理:abc\"efg
时间: 2024-10-30 07:03:05

《深入理解Elasticsearch(原书第2版)》一第1章Elasticsearch简介1.1 Apache Lucene简介的相关文章

《深入理解Elasticsearch(原书第2版)》一2.2.2 回到Apache Lucene

2.2.2 回到Apache Lucene 现在我们回到Lucene.如果你还记得Lucene倒排索引是如何构建的,你会指出倒排索引中包含了词项.词频以及文档指针(如果忘了,请重新阅读1.1节).现在我们看看之前存储到clients索引中的数据大概是如何组织的. Term这一列非常重要.如果我们去探究Elasticsearch和Lucene的内部实现,将会发现前缀查询被改写为下面这种查询: 我们可以用Elasticsearch API来检查重写片段.首先,使用Explain API执行如下命令:

《深入理解Elasticsearch(原书第2版)》——第1章 Elasticsearch简介 1.1 Apache Lucene简介

第1章 Elasticsearch简介 我们希望读者通过阅读本书来获取和拓展关于Elasticsearch的基本知识.假设读者已经知道如何使用Elasticsearch进行单次或批量索引创建,如何发送请求检索感兴趣的文档,如何使用过滤器缩减检索返回文档的数量,以及使用切面/聚合(faceting/aggregation)机制来计算数据的一些统计量.不过,在接触Elasticsearch提供的各种令人激动的功能之前,希望读者能对Apache Lucene有一个快速的了解,因为Elasticsear

《代码之殇》(原书第2版)——第3章 根除低下的效率 2006年7月1日

2006年7月1日:"停止写规范书,跟功能小组呆在一起" 我不是项目经理(Program Manager,PM),我也从来没有担任过项目经理,我将来也不可能成为一名项目经理.这并不是因为我个人对项目经理的抵触,其实,我的朋友之中不乏出色的项目经理.很显然,我没有权利去教导项目经理应该怎么去做他们的工作. 尽管如此,项目经理应该停止写规范书.就这么简单!他们在浪费我的时间,浪费组织的时间,浪费整个公司的时间.你几乎可以听到残留着的.细微的.嘎吱嘎吱的声音,因为规范书像白蚁一样在一口一口咬

《代码之殇》(原书第2版)——第3章根除低下的效率 2007年2月1日

2007年2月1日:"糟糕的规范书:该指责谁?" 规范书基本上都是可怕的.不仅仅指项目管理规范书,而且也包括开发规范书和测试规范书.我说的"可怕",主要是指难以撰写,难以使用,而且难以维护.你要知道,这很可怕!规范书往往还是不完善的,组织得很差,并且没有得到充分的复审.规范书永远都是这个样子,也看不到有任何变好的迹象. 为此,我想要指责项目经理,部分原因是因为我喜欢这么做,但更主要的还是因为他们是糟糕规范书的始作俑者.然而,事实不允许我指责项目经理.人人都在写糟糕的

《代码之殇》(原书第2版)——第2章 过程改进,没有灵丹妙药 2006年3月1日

2006年3月1日:"敏捷子弹" 我很难做出判断.也许你可以帮我.我不能断定以下两种观点,哪种更糟心:一种观点认为使用"敏捷"方法,并且恨不得微软在全公司范围内采用它,用它解决我们面临的所有麻烦:另一种观点认为敏捷是被一些无知的学者鼓吹出来的,它实际上是一种改头换面的愚昧方法,它让开发者不用承担任何责任.这是个两难的决定,两种观点都会使我有种作呕的感觉. 作者注:这是我最喜欢的栏目之一,因为其间爱恨交错不能自已.尽管它并不完美,但我在这个主题上的评论还是相当公允的.

ROS机器人程序设计(原书第2版)第1章 ROS Hydro系统入门

第1章 ROS Hydro系统入门 欢迎开始阅读本书第1章.本章将介绍如何安装ROS系统,它是一种新的标准化机器人系统软件框架.本书是基于ROS Fuerte的<ROS机器人程序设计>一书的升级版.通过ROS,你可以使用大量的示例代码和开源程序轻松地完成机器人编程和控制.同时,你还能够理解如何使用各种传感器与执行器,并为你的机器人增加新的功能,如自动导航和视觉感知等.得益于开源理念,以及持续开发最先进算法并不断提供新功能的开源社区,ROS不断进步完善. 通过本书,你将学习到如下内容: 在特定版

《代码之殇》(原书第2版)——第1章 项目管理失当,2008年9月1日

2008年9月1日:"我得估算一下" 尽管"你的任务估算是怎么产生的?"这样的疑问总是列在诸如"不要对你的项目经理或同事抱怨"的话题之首.但当我与刚出道的工程师们讨论问题时,首先的话题不是估算,而是职业发展和一些大众话题.这就是为什么问题总是在高谈阔论中变得无法控制.估算就是在预测未来,有太多的问题是未知而不可预见的,因而想为一个精神错乱的暴君提供一个精确的估算简直不可能.是不是?肯定是这样的,对吧? 错了.估算来自于软件工程师在规范的基础上对最

代码之殇》(原书第2版)——第1章 项目管理失当 2010年5月1日

2010年5月1日:"敏捷的团队合作" 我用Scrum已经7年了,而后面6年我一直写关于它的文章.Scrum的概念太吸引人了--规则多变.自我管理的团队在短而固定的周期内周而复始地进行一系列小环节(或功能)工作,并不断提升水平.很多微软团队的成功都来自于此.让人犯昏的是高层的项目经理与团队层的Scrum工程师仍存在严重隔阂. 很多高层及中层的项目经理认为Scrum是混乱的.随意的.危险的并毫无意义的,会使大家对计划失去信心:而很多Scrum迷认为项目计划是种浪费,会引起混乱,毫无价值,

ROS机器人程序设计(原书第2版)第3章 可视化和调试工具

第3章 可视化和调试工具 ROS附带了大量功能强大的工具,帮助用户和开发人员可视化和调试代码,以便检测并解决软硬件问题.其中包括消息日志系统(类似log4cxx).诊断消息.可视化以及检测工具.这些工具展示了哪些节点正在运行和它们是如何连接的.   本章我们还会展示如何用GDB调试器调试ROS节点,介绍用于日志记录的API,以及如何设置日志记录级别.接着,我们将解释如何用ROS工具集检测哪些进程正在运行以及它们之间通信的内容.例如,在下图所示的系统可视化图中可以看到正在运行的节点以及用连线表示的

《算法导论(原书第3版)》一本章注记

本章注记 关于算法的一般主题存在许多优秀的教科书,包括由以下作者编写的那些:Aho.Hopcroft和Ullman[5,6],Baase和Van Gelder[28],Brassard和Bratley[54],Dasgupta.Papadimitriou和Vazirani[82],Goodrich和Tamassia[148],Hofri[175],Horowitz.Sahni和Rajasekaran[181],Johnsonbaugh和Schaefer[193],Kingston[205],Kl