Elasticsearch可以说是企业级搜索应用的最佳选择。相较于传统的关系型数据库,Elasticsearch更适合于存储海量数据并对其进行全文检索和数据分析(聚合)。同时ES适合进行结构化/非结构化查询。下面介绍Elasticsearch中的数据存储方式。

Elasticsearch系列教程
- Elasticsearch教程之一:介绍
- Elasticsearch教程之二:索引,分词及映射
- Elasticsearch教程之三:API
- Elasticsearch教程之四:AWS OpenSearch
- Elasticsearch教程之五:Opensearch Node.js客户端的使用
- Elasticsearch教程之六:Python客户端的使用
- Elasticsearch教程之七:在OpenSearch中使用聚合实现Facet
Elasticsearch中的几个重要概念
ES是面向文档(document oriented)的,整个文档/对象会被存储并可被搜索。正因为如此,ES支持全文检索。
ES中的索引(index)就相当于数据库中的库(database)
ES中的类型(type)就相当于数据库中的表(table)
ES中的文档(document)就相当于数据库中的记录(record)
自从ES6.x之后,一个index中只能有一个type,因此检索方式由早期的:
http://localhost:9200/tutorial/helloworld/1
更改为(无需指定type):
http://localhost:9200/tutorial/_doc/1
Elasticsearch中的索引
正向索引(forward index)
所谓正向索引,就是通过键查找值(key => value)的过程。比如:学生信息系统中,根据学号查找学生具体信息。或者,在一个数组中通过下标访问数组元素。
正向索引得优点就是其简单性。因此只能在一些简单场景下使用。当需要从不同数据源查询不同字段时,尤其是海量数据时,其速度是远不能满足要求的。(比如在数据库查询中的模糊匹配通常无法通过索引(B Tree),而是进行全局扫描来实现,因此其效率较低。)同时,在进行全文检索的时候,较难实现。比如:在数据库中搜索“凤凰传奇”和“传奇凤凰”时,需要通过不同的关键字查询。针对更为复杂的场景,关系型数据库查询效率很低。
倒排索引(inverted index)
倒排索引是通过字/词来查找索引的过程。它记录了出现关键字文档的ID及该关键字在文档中的位置。
倒排索引主要构成:
- 单词字典(Term Dictionary):通过B+Trees实现,通常存储在内存中。
- 倒排列表(Posting List)
而倒排列表中包含的信息有:
- docid
- TF(Term Frequency): 单词出现频率,用于计算相关性
- position:分词后单词所在位置
- offset:单词在文档中起始位置,用于实现标红
倒排索引的优点是其全文检索的效率远高于正向索引。它的缺点则是倒排表的建立和维护都非常复杂。
Elasticsearch分词
Elasticsearch分词器介绍
所谓分词,就是将文本转换成一系列单词(terms / tokens)。ES分词主要包括三部分的工作:
- Character Filter: 对原始文本进行处理,比如:过滤掉特殊字符,html标签等。
- Tokenizer:对原始文本进行分词。
- Token Filters:对分此后的关键字进行加工,例如:去除语气词等。
对ES默认分词器的测试
在Kibana中输入:
POST _analyze
{
"analyzer": "standard",
"text": "elastic search"
}
其返回值为:
{
"tokens" : [
{
"token" : "elastic",
"start_offset" : 0,
"end_offset" : 7,
"type" : "<ALPHANUM>",
"position" : 0
},
{
"token" : "search",
"start_offset" : 8,
"end_offset" : 14,
"type" : "<ALPHANUM>",
"position" : 1
}
]
}
测试ES索引中某个字段上的分词器:
POST testindex/_analyze
{
"field": "message",
"text": "elastic search is great!"
}
测试标准分词器和自定义过滤器:
POST _analyze
{
"tokenizer": "standard",
"filter": ["uppercase"],
"text": "elastic search"
}
以下会过滤掉html标签:
POST _analyze
{
"tokenizer": "keyword",
"char_filter": ["html_strip"],
"text": "<li>Apple</li><li>Pear</li>"
}
ES自带分词器:Standard, Simple, Whitespace, Stop, Pattern, Language
Elasticsearch mapping (映射)
mapping用来定义index中的类型(type),使用的分词器等信息。类似于数据库中的schema。当没有指定时,ES会自动创建mapping。
获取索引中的mapping:
GET testindex/_mapping
例如:在创建索引时指定mapping:
PUT test_index
{
"mappings": {
"properties": {
"title": {
"type":"text"
},
"name": {
"type":"keyword"
}
}
}
}
需要注意:如果使用默认的mapping,字段类型是text,可以分词,但不能进行聚合操作,比如:返回facet查询。因此,通常需要自己定义mapping,也就是数据类型:
PUT testfacet/_mapping
{
"properties" : {
"score" : {
"type" : "integer"
},
"name" : {
"type" : "keyword"
},
"subject" : {
"type" : "keyword"
}
}
}
Dynamic mapping: 如果插入的字段不在mapping中定义,那么ES会自动根据字段值来查找类型。
“dynamic”的可选值包括:
- true: 允许自动添加新字段
- false:不允许自动新增字段,但仍可以写入。写入后无法查询。
- strict: 添加新字段会报错