概述
Elastic官方对Elasticsearch的定义是这样的:Elastic is a highly scalable open-source full-text search and analytics engine。可见官方定义中,Elasticsearch被视为一种高度可伸缩的全文检索和分析引擎,这体现了Elasticsearch具有强大的文档检索和分析能力。Elasticsearch底层基于Apache Lucene,而Lucene本身一种早就闻名于世的全文检索引擎和工具包。Elasticsearch在此基础上进行了封装,不仅继承了Lucene所有优点,还大大降低了使用和开发的复杂度。所以从这个角度来说,Elasticsearch是一种全文检索和分析引擎。 但事实上,Elasticsearch也包含了强大的数据存储能力,它所检索的数据不依赖于外部数据源,而由Elasticsearch统一管理。不仅如此,Elasticsearch还具备创建数据分片(Shard)和数据副本(Replica)的能力,可以满足大数据量下的高可用性和高性能要求。所以在许多文献中,Elasticsearch也被归类为一种基于文档的NoSQL数据库,类似于MongoDB。事实上,正是这种优秀的存储能力,才使Elasticsearch具备了强大的检索和分析能力。
全文检索和倒排索引
先以对比传统数据库的方式来解释一些基本概念。
- 索引(Index)相当于库;
- 映射类型(Mapping Type)相当于表;
- 文档(Document)相当于行;
- 字段(Field)相当于列。
全文检索
先来解释一下什么叫全文检索。数据库检索的目的是从一系列数据中,根据某一或某些数据特征将特定的数据找出来。从数据检索的角度来看,数据大体上可以分为两种类型:一种是结构化数据;另一种是非结构化数据。结构化数据将数据具有的特征事先以结构化的形式定义好,数据有固定的格式或有限的长度。典型的结构化数据就是传统关系型数据库的表结构,数据特征直接体现在表结构的字段上,所以根据某一特征做数据检索很直接,速度也比较快。比如,根据商品的名称将该商品全部查找出来,通过一条SQL语句就能实现。如果想要提高查找速度,只要在商品名称上创建索引就可以了。许多应用系统都是建立在结构化数据的基础之上,例如财务软件、CRM、MIS等。 非结构化数据则完全不同,他们没有预先定义好的结构化特征,也没有固定格式和固定长度。典型的非结构化数据包括文章、图片、视频、网页、邮件等。其中像HTML网页这种具有一定格式的文档也称为半结构化数据。显而易见,相比结构化数据,非结构化数据的检索要难得多。在对他们的检索中,像文章、网页、邮件这种全文本(Full-text)数据的检索需要占了大多数,而且与图片、视频等非文本数据的检索完全不同,因此形成了一门独立的学科,这就是全文检索。包括Elastic官网在内的很多文献中,经常称全文本数据中的一条数据为文档(Document),而称存储全文本数据的数据库为全文本数据库。所以简单来说,全文本检索是指在全文数据中检索单个文档或文档集合的搜索技术,而Elasticsearch从这个意义来说也可以理解为是一个全文数据库。 与结构化查询相比,全文检索面临的最大问题就是性能问题。全文检索最一般的应用场景是根据一些关键字查询网页。显然,如果没有对文档做特别处理,查找的办法似乎只能是逐条比对。具体来说就是先将所有文档都读取出来,再对文档内容做逐行扫描看是否包含这些关键字。例如,Linux的grep命令就是通过这种算法实现的。但这种方法在数据量非常大的情况下就像大海捞针一样,速度会非常慢。而类似互联网搜索引擎这样的应用面对的文档往往都是天文数字,所以需要有一种更好的办法实现全文检索。 关系型数据库提示数据查询速度的常用方法是给字段添加索引,有了索引的字段会根据字段值排序并创建类似排序二叉树的数据结构(如B树),这样就可以利用二分查找等算法提升查询速度。所以在字段添加索引后,通过这些字段做查询时速度呢能得到非常明显的提升。但由于添加索引后需要对字段排序,所以增加和删除数据时速度会变慢,并且还需要额外的空间存储索引。这是典型的利用空间换取时间的策略。普通的索引对全文检索并适用,因为这种索引使用字段整体值参与排序,所以在检索时也需要通过字段的整体值做查询条件。而全文检索一般是查询包含某一或某些关键字的文档,所以通过文档整体值建立的索引对提供查询速度是没有任何帮助的。为了解决这个问题,人员创建了一种新索引方法,这种索引方法就是倒排索引(Inverted Index)。
倒排索引
倒排索引先将文档中包含的关键字全部提取出来,然后再将关键字与文档的对应关系保存起来,最后再对关键字本身做索引排序。用户在检索某一关键字时,可以先对关键字的索引进行查找,再通过关键字与文档的对应关系找到所在文档。这类似于查字典一样,字典的拼音表和部首中的内容就是关键字与文档的对应关系。为了说明倒排索引的基本思想,以下面两条文档为例:
文档一:I love elasticsearch.
文档二:I love logstash.
针对这两份文档创建倒排索引的第一步,是先对文档提取关键字。对于英文来说比较简单按空格分隔即可,两份文档共提取I、love、elasticsearch和logstash四个关键字。接下来就是建立关键字与文档之间的对应关系,即标识关键字都被哪些文档包含。下面通过一种形象的形式来表示这种对应关系。 有了倒排索引,用户检索就可以在倒排索引中快速定位到包含关键字的文档。倒排索引与关系型数据库索引类似,会根据关键字做排序。但关系型数据库索引一般是对主键创建,然后索引指向数据内容;而倒排索引则正好相反,它是针对文档内容创建索引,然后索引指向主键(文档一、文档二),这就是这种索引被称为倒排索引的原因。 从以上分析可以看出,倒排索引实际上是对全文数据结构化的过程。对于存储在关系型数据库中的数据来说,他们依赖于人的预先分析将数据拆解为不同字段,所以在数据插入时就已经是结构化的;而在全文数据库中,文档在插入时还不是结构化的,需要应用程序根据规则自动提前关键字,并形成关键字与文档之间的结构化对应关系。由于文档在创建时需要提前关键字并创建索引,所以向全文数据库添加文档比关系型数据库要慢一些。 不难看出,全文检索中提取关键字时非常重要的一步。这些预先提取出来的关键字,在Elasticsearch及全文检索的相关文献中一般称为词项(Term)。文档的词项提取在Elasticsearch中称为文档分析(Analysis),是整个全文检索中较为核心的过程。这个过程必须要区分哪些是词项,哪些不是。对于英文来说,还被必须要知道apple和apples指的同一个东西,而run和running指的是同一个动作。对于中文来说就更麻烦了,因为中文词语不以空格分隔,所以面临的第一个难题是如何将词语分辨出来。
Elasticsearch索引
|