一、Elasticsearch
- 强大的搜索和分析能力:
- Elasticsearch 是一个基于 Lucene 的分布式搜索和分析引擎。它能够快速地对大量数据进行全文搜索、结构化搜索和复杂的数据分析操作。
- 对于大型数据集,它可以高效地处理各种查询需求,包括关键词搜索、范围查询、聚合分析等。例如,在电商领域,可以快速搜索商品名称、描述等信息,同时还能对销售数据进行聚合分析,如按时间段统计销售额、销量等。
- 分布式架构:
- Elasticsearch 设计为分布式系统,可以轻松地扩展到处理大规模数据集。它可以将数据分布在多个节点上,实现并行处理和高可用性。
- 当数据量不断增长时,可以通过添加更多的节点来扩展系统的存储和处理能力,而不会对系统的性能产生显著影响。
- 这种分布式架构还提供了自动故障转移和数据冗余功能,确保数据的安全性和可靠性。
- 实时性:
- Elasticsearch 支持实时索引和搜索,数据可以在写入后立即被搜索到。这对于需要实时分析数据的场景非常重要。
- 例如,在日志分析中,可以实时监控系统日志,及时发现问题并进行处理。在金融领域,可以实时分析交易数据,以便做出及时的决策。
- 易于使用和集成:
- Elasticsearch 提供了丰富的 API 和工具,使得开发人员可以轻松地与各种编程语言和技术进行集成。
- 它还具有友好的用户界面,如 Kibana,可以方便地进行数据可视化和分析。开发人员可以通过简单的配置和查询语句,快速实现复杂的搜索和分析功能。
二、Elasticsearch 结构
-
节点(Node):
- Elasticsearch 集群由一个或多个节点组成。每个节点是一个独立的服务,可以存储数据、处理查询请求,并与其他节点进行通信。
- 节点可以分为主节点(Master Node)和数据节点(Data Node)。主节点负责管理集群的状态,如分配分片、处理节点加入和离开等。数据节点负责存储数据和执行查询操作。
-
索引(Index):
- 索引是 Elasticsearch 中存储数据的逻辑空间。它类似于关系数据库中的数据库,可以包含多个类型(Type)的文档。
- 索引由一个或多个分片(Shard)组成,每个分片是一个独立的 Lucene 索引。分片可以分布在不同的节点上,实现数据的分布式存储和并行处理。
-
类型(Type):
- 在一个索引中,可以定义多个类型。类型用于对具有相似结构的文档进行分类。例如,在一个电商索引中,可以定义商品类型和订单类型。
- 每个类型有自己的映射(Mapping),定义了文档的字段和数据类型。
-
文档(Document):
- 文档是 Elasticsearch 中存储的基本单位。它是一个 JSON 格式的对象,包含了一组字段和对应的值。
- 文档通过唯一的 ID 进行标识,可以被索引、搜索和更新。
-
分片(Shard):
- 分片是 Elasticsearch 中数据的最小存储单元。每个分片是一个独立的 Lucene 索引,可以分布在不同的节点上。
- 分片分为主分片(Primary Shard)和副本分片(Replica Shard)。主分片负责存储原始数据,副本分片用于提供数据的备份和高可用性。
-
映射(Mapping):
- 映射定义了文档的字段和数据类型。它类似于关系数据库中的表结构定义。
- 映射可以在创建索引时指定,也可以在后期动态更新。它包括字段的名称、数据类型、分析器、索引选项等。
三、倒排索引
Elasticsearch 使用倒排索引来实现高效的搜索功能。下面详细介绍其倒排索引原理:
1、什么是倒排索引
倒排索引(Inverted Index)是一种用于快速检索的数据结构。与传统的正向索引(如书籍的目录,根据内容的位置来查找内容)不同,倒排索引是根据内容来查找其位置。在文本搜索领域,倒排索引将每个词(或称为"词条""术语")与包含该词的文档列表相关联。
2、Elasticsearch 倒排索引的构成
Elasticsearch 的倒排索引主要由以下几个部分组成:
-
词条(Terms):
- 这是索引中的基本单元,通常是经过分词器处理后的单词或短语。例如,对于文本"Elasticsearch is a powerful search engine",可能会被分解为"elasticsearch""is""a""powerful""search""engine"等词条。
-
文档列表(Postings List):
- 对于每个词条,都有一个对应的文档列表,记录了包含该词条的所有文档的信息。文档信息通常包括文档 ID、词频(Term Frequency,TF,该词条在文档中出现的次数)、位置信息(该词条在文档中的具体位置,例如在句子中的位置)等。
-
词典(Dictionary):
- 词典是所有词条的集合,通常以某种数据结构(如哈希表、B 树等)进行存储,以便快速查找词条。词典的作用是将用户输入的查询词快速转换为对应的词条,然后查找倒排索引中的文档列表。
3、倒排索引的构建过程
-
文本分析(Text Analysis):
- 当向 Elasticsearch 中添加文档时,首先会对文档的内容进行文本分析。这个过程包括分词、去除停用词、词干提取等操作。
- 分词是将文本分割成一个个独立的词条。例如,"I love Elasticsearch"可能会被分割成"i""love""elasticsearch"三个词条。
- 去除停用词是指去除一些常见的、对搜索意义不大的词,如"a""the""is"等。
- 词干提取是将单词还原为其基本形式,例如将"loves""loving""loved"都还原为"love"。
-
词条生成与存储:
- 经过文本分析后,得到的词条会被添加到倒排索引中。如果词条已经存在于词典中,则将当前文档的信息添加到该词条的文档列表中;如果词条不存在,则在词典中创建新的词条,并为其创建一个新的文档列表。
-
文档列表更新:
- 对于每个词条的文档列表,会记录文档 ID、词频和位置信息等。当有新的文档包含该词条时,文档列表会被更新。例如,如果新文档的 ID 为 100,并且包含词条"elasticsearch",则会在"elasticsearch"的文档列表中添加文档 ID 为 100 的记录,并更新词频和位置信息。
4、倒排索引的搜索过程
-
查询分析:
- 当用户输入查询时,Elasticsearch 会对查询进行与文档添加时类似的文本分析操作,将查询转换为一系列词条。
-
词条查找:
- 根据查询中的词条,在词典中查找对应的文档列表。
-
文档评分:
- 对于每个找到的文档,Elasticsearch 会根据一定的算法计算文档的相关性得分。得分通常考虑因素包括词频(TF,词条在文档中出现的次数)、逆文档频率(Inverse Document Frequency,IDF,衡量词条在整个索引中的稀有程度)、文档长度等。
- 例如,一个词条在某个文档中出现的次数越多,并且该词条在整个索引中出现的文档越少,那么这个文档的得分就越高,说明它与查询的相关性越大。
-
结果排序:
- 根据文档的得分,对搜索结果进行排序,得分高的文档排在前面。
5、倒排索引的优势
-
快速搜索:
- 倒排索引可以快速定位包含特定词条的文档,大大提高了搜索的效率。无论索引中有多少文档,都可以在很短的时间内返回搜索结果。
-
灵活的查询:
- 支持各种复杂的查询,如全文搜索、短语搜索、布尔查询等。可以根据用户的需求进行精确匹配、模糊匹配、范围查询等操作。
-
可扩展性:
- Elasticsearch 的分布式架构使得倒排索引可以轻松地扩展到处理大规模数据集。可以通过添加更多的节点来扩展索引的存储和处理能力,而不会影响搜索性能。
二、Elasticsearch 的范例
以下是一个使用 Elasticsearch 进行关键词搜索、范围查询和聚合分析的范例。
假设我们有一个电商商品索引,包含商品名称、价格、库存等字段。
一、关键词搜索
查找名称中包含"手机"的商品:
json
GET /ecommerce/_search
{
"query": {
"match": {
"name": "手机"
}
}
}
二、范围查询
查找价格在 1000 到 2000 元之间的商品:
json
GET /ecommerce/_search
{
"query": {
"range": {
"price": {
"gte": 1000,
"lte": 2000
}
}
}
}
三、聚合分析
- 统计不同品牌的商品数量:
json
GET /ecommerce/_search
{
"size": 0,
"aggs": {
"brands": {
"terms": {
"field": "brand"
}
}
}
}
- 计算平均价格:
json
GET /ecommerce/_search
{
"size": 0,
"aggs": {
"average_price": {
"avg": {
"field": "price"
}
}
}
}
求中位数
假设已经有一个名为"products"的索引,包含"price"字段表示商品价格。可以使用以下命令添加一些示例数据:
json
POST /products/_doc/1
{
"price": 10
}
POST /products/_doc/2
{
"price": 20
}
POST /products/_doc/3
{
"price": 30
}
POST /products/_doc/4
{
"price": 40
}
POST /products/_doc/5
{
"price": 50
}
使用聚合分析计算中位数
可以使用以下查询来计算价格的中位数:
json
GET /products/_search
{
"size": 0,
"aggs": {
"median_price": {
"percentiles": {
"field": "price",
"percents": [50]
}
}
}
}
在这个查询中,我们使用了百分位聚合,指定了要计算的字段为"price",并且只计算 50%这个百分位,即中位数。
结果解析
返回的结果类似如下:
json
{
"took": 12,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 5,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"median_price": {
"values": {
"50.0": 30
}
}
}
}
这里的"50.0"对应我们请求的 50%百分位,值为 30,表示近似的中位数价格是 30。
需要注意的是,这种方法只是近似计算中位数,对于非常大的数据集可能不够准确。在实际应用中,可以根据具体情况调整聚合的设置和使用更复杂的方法来获得更准确的结果。