一、前言
介绍我们在前面已经知道ElasticSearch底层的写入是基于lucence依进行doc写入的。ElasticSearch作为一款分布式系统,在写入数据时还需要考虑很多重要的事项,比如:可靠性、原子性、一致性、实时性、隔离性、性能等多个指标。
ElasticSearch是如何做到的呢?下面我们针对ElasticSearch的写入进行分析。
二、lucence写
2.1 增删改
ElasticSearch拿到一个doc后调用lucence的api进行写入的。
public long addDocument();
public long updateDocuments();
public long deleteDocuments();
如上面的代码所示,我们使用lucence的上面的接口就可以完成文档的增删改操作。在lucence中有一个核心的类IndexWriter负责数据写入和索引相关的工作。
//1. 初始化indexwriter对象
IndexWriter writer = new IndexWriter(new Directory(Paths.get("/index")), new IndexWriterConfig());
//2. 创建文档
Document doc = new Document();
doc.add(new StringField("empName", "王某某", Field.Store.YES));
doc.add(new TextField("content", "操作了某菜单", Field.Store.YES));
//3. 添加文档
writer.addDocument(doc);
//4. 提交
writer.commit();
以上代码演示了最基础的lucence的写入操作,主要涉及到几个关键点:
初始化:
Directory是负责持久化的,他的具体实现有很多,有本地文件系统、数据库、分布式文件系统等待,ElasticSearch默认的实现是本地文件系统。
Document:
Document就是es中的文档,FiledType定义了很多索引类型。这里列举几个常见的类型:
-
stored:字段原始内容存储
-
indexOptions:
(NONE/DOCS/DOCS_AND_FREQS/DOCS_AND_FREQS_AND_POSITIONS/DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS),倒排索引的选项,存储词频、位置信息等。
-
docValuesType:正排索引,建立一个docid到field的的一个列存储。
-
一些其它的类型
IndexWriter:
IndexWriter在doc进行commit后,才会被持久化并且是可搜索的。
IndexWriterConfig:
IndexWriterConfig负责了一些整体的配置参数,并提供了方便使用者进行功能定制的参数:
-
Similarity:这个是搜索的核心参数,实现了这个接口就能够进行自定义算分。lucence默认实现了前面文章提到的TF-IDF、BM25算法。
-
MergePolicy:合并的策略。我们知道ElasticSearch会进行合并,从而减少段的数量。
-
IndexerThreadPool:线程池的管理。
-
FlushPolicy:flush的策略。
-
Analyzer:定制分词器。
-
IndexDeletionPolicy:提交管理。
PS:在ElasticSearch中,为了支持分布式的功能,新增了一些系统默认字段:
-
_uid,主键,在写入的时候,可以指定该Doc的ID值,如果不指定,则系统自动生成一个唯一的UUID值。
-
_version,版本字段,version来保证对文档的变更正确的执行,更新文档时有用。
-
_source,原始信息,如果后面维护不需要reindex索引可以关闭该字段,从而节省空间
-
_routiong,路由字段。
-
其它的字段
2.2. 并发模型
上面我们知道indexwriter负责了ElasticSearch索引增删改查。那它具体是如何管理的呢?
(图:IndexWritter模型)
2.2.1. 基本操作
关键点:
-
DocumentsWriter处理写请求,并分配具体的线程DocumentsWriterPerThread
-
DocumentsWriterPerThread具有独立内存空间,对文档进行处理DocumentsWriter触发一些flush的操作。
-
DocumentsWriterPerThread中的内存In-memory buffer会被flush成独立的segement文件。
-
对于这种设计,多线程的写入,针对纯新增文档的场景,所有数据都不会有冲突,非常适合隔离的数据写入方式