时间 | 版本 | 修改人 | 描述 |
---|---|---|---|
2024年9月2日14:44:29 | V0.1 | 宋全恒 | 新建文档 |
简介
elasticsearch使用流程
基本使用流程为
- 创建索引
- 添加文档
- 检索分析
1. 创建索引
- 定义索引结构:在 Elasticsearch 中,
索引类似于关系数据库中的表
。创建索引时,你可以定义字段的映射(类似于表的列和数据类型),这包括每个字段的数据类型和其他属性(如是否需要全文搜索,是否需要索引等)。 - 指定分片和副本:创建索引时,还可以指定索引的分片和副本数量,以便优化存储和查询性能。
示例:
bashCopy codePUT /my_index
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"field1": {
"type": "text"
},
"field2": {
"type": "keyword"
}
}
}
}
number_of_shards
和number_of_replicas
设置了索引的分片和副本数量。properties
下定义了字段的类型,如text
、keyword
等。
2. 向索引中添加文档
- 插入文档:一旦索引创建完毕,你可以向索引中插入数据,
这些数据被称为文档
。每个文档都有一个唯一的ID标识符(可以由用户指定,也可以由 Elasticsearch 自动生成)。 - 文档结构:文档是以 JSON 格式存储的,字段和数据结构不需要完全一致,Elasticsearch 可以处理不同的字段。
示例:
bashCopy codePOST /my_index/_doc/1
{
"field1": "This is some text",
"field2": "some_value"
}
- 这里,我们将一个文档插入到名为
my_index
的索引中,并且指定了文档 ID 为1
。
索引和文档的关系
- 索引相当于数据库表:在 RDBMS 中,你创建一个表,然后向表中插入行。在 Elasticsearch 中,你首先创建索引(定义字段及其类型),然后向索引中添加文档(类似于向表中插入行)。
- 文档相当于表中的行:文档是 Elasticsearch 中的基本存储单元,类似于关系数据库中的一行。每个文档由一个 JSON 对象表示,包含一组键值对(字段和值)。
需要注意的事项
- 动态索引:Elasticsearch 支持动态映射,可以在没有事先定义索引的情况下直接插入数据,Elasticsearch 会根据文档中的字段自动推断类型并创建索引。这种方法虽然方便,但在生产环境中最好是手动创建和管理索引结构,以确保数据的一致性和查询的高效性。
- 索引管理:定期管理索引,避免索引过多或数据分片不均匀,可能需要设置索引生命周期策略(ILM)来管理索引的存储和归档。
演示
演示场景
使用elasticsearch,演示新建一个索引,基本的场景是存储一个班级中每个人的成绩,成绩表包含姓名,学号,语文成绩和数学成绩,英语成绩,使用接口演示增删改查。
索引创建
PUT /class_scores
{
"mappings": {
"properties": {
"student_id": {
"type": "keyword"
},
"name": {
"type": "text"
},
"chinese_score": {
"type": "integer"
},
"math_score": {
"type": "integer"
},
"english_score": {
"type": "integer"
}
}
}
}
发起请求后,响应如下:
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "class_scores"
}
文档管理
添加文档
POST /class_scores/_doc/1
{
"student_id": "202401",
"name": "Alice",
"chinese_score": 85,
"math_score": 90,
"english_score": 88
}
POST /class_scores/_doc/2
{
"student_id": "202402",
"name": "Bob",
"chinese_score": 78,
"math_score": 82,
"english_score": 80
}
POST /class_scores/_doc/3
{
"student_id": "202403",
"name": "Charlie",
"chinese_score": 92,
"math_score": 95,
"english_score": 94
}
创建文档3的响应为
{
"_index": "class_scores",
"_id": "3",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 2,
"_primary_term": 1
}
检索数据
GET /class_scores/_doc/1
GET /class_scores/_search
{
"query": {
"match_all": {}
}
}
GET /class_scores/_search
{
"query": {
"range": {
"chinese_score": {
"gte": 80
}
}
}
}
更新文档
更新文档之后,数学成绩更新为95,重新检索,可以得到
{
"_index": "class_scores",
"_id": "1",
"_version": 2,
"_seq_no": 3,
"_primary_term": 1,
"found": true,
"_source": {
"student_id": "202401",
"name": "Alice",
"chinese_score": 85,
"math_score": 95,
"english_score": 88
}
}
删除文档
DELETE /class_scores/_doc/2
删除的响应为
{
"_index": "class_scores",
"_id": "2",
"_version": 2,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 4,
"_primary_term": 1
}
删除了2号文档之后,全量检索,可以看到2号文档已经不存在了。
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "class_scores",
"_id": "1",
"_score": 1,
"_source": {
"student_id": "202401",
"name": "Alice",
"chinese_score": 85,
"math_score": 95,
"english_score": 88
}
},
{
"_index": "class_scores",
"_id": "3",
"_score": 1,
"_source": {
"student_id": "202403",
"name": "Charlie",
"chinese_score": 92,
"math_score": 95,
"english_score": 94
}
}
]
}
}
全文检索
索引
PUT /class_scores
{
"mappings": {
"properties": {
"student_id": {
"type": "keyword"
},
"name": {
"type": "text"
},
"chinese_score": {
"type": "integer"
},
"math_score": {
"type": "integer"
},
"english_score": {
"type": "integer"
},
"remarks": {
"type": "text"
}
}
}
}
其实相当于添加了一个text字段,remarks表示评价,对于该学生的评价,
插入数据
插入一些数据
POST /class_scores/_doc/1
{
"student_id": "202401",
"name": "Alice",
"chinese_score": 85,
"math_score": 90,
"english_score": 88,
"remarks": "Excellent performance in mathematics."
}
POST /class_scores/_doc/2
{
"student_id": "202402",
"name": "Bob",
"chinese_score": 78,
"math_score": 82,
"english_score": 80,
"remarks": "Needs improvement in Chinese language."
}
POST /class_scores/_doc/3
{
"student_id": "202403",
"name": "Charlie",
"chinese_score": 92,
"math_score": 95,
"english_score": 94,
"remarks": "Outstanding in all subjects."
}
执行全文检索
现在,假设我们想要搜索 remarks
字段中包含 “improvement” 或 “outstanding” 这些关键词的文档。我们可以使用 match
查询来执行全文搜索。
GET /class_scores/_search
{
"query": {
"match": {
"remarks": "improvement"
}
}
}
Elasticsearch 会根据匹配的相关性对结果进行评分和排序。完全匹配的文档得分更高,排名也会更靠前。
同时搜索 “Charlie” 和 “outstanding”
GET /class_scores/_search
{
"query": {
"bool": {
"must": [
{ "match": { "name": "Charlie" }},
{ "match": { "remarks": "outstanding" }}
]
}
}
}
综合查询:多个学科成绩范围
如果你需要检索语文、数学和英语成绩都在 70 到 90 之间的文档,可以将多个 range
查询条件结合在一起:
bashCopy codeGET /class_scores/_search
{
"query": {
"bool": {
"must": [
{
"range": {
"chinese_score": {
"gte": 70,
"lte": 90
}
}
},
{
"range": {
"math_score": {
"gte": 70,
"lte": 90
}
}
},
{
"range": {
"english_score": {
"gte": 70,
"lte": 90
}
}
}
]
}
}
}
操作子分类
基本查询
match: 用于执行全文搜索或关键字匹配。适用于分析过的字段(如 text
类型)
term: 用于精确匹配字段值。适用于未分析的字段(如 keyword
类型)
range:用于查找字段值在指定范围内的文档。
复合查询
bool: 用于组合多个查询条件,允许使用 must
、should
、must_not
和 filter
子句。
子句:
must
:必须匹配的条件。should
:应该匹配的条件(至少一个)。must_not
:必须不匹配的条件。filter
:用于过滤文档,不影响相关性评分。
示例
{
"query": {
"bool": {
"must": [
{ "match": { "field1": "value1" }},
{ "range": { "field2": { "gte": 10 }}}
],
"should": [
{ "term": { "field3": "value3" }}
],
"must_not": [
{ "term": { "field4": "value4" }}
],
"filter": [
{ "range": { "field5": { "lte": 100 }}}
]
}
}
}
constant_score:对查询结果应用固定的评分(分数),可以提高查询性能。
特殊查询
match_phrase:用于查找精确的短语匹配。
wildcard:用于匹配具有通配符(如 *
和 ?
)的字段值。
fuzzy:用于模糊匹配,允许一定的字符差异(类似拼写错误的容错)。
聚合查询
这些查询用于对文档进行分组、汇总或统计分析。
terms
聚合:用于统计字段的不同值及其出现次数。
range
聚合:用于将字段值划分为多个范围,并统计每个范围的文档数量。
示例:
{
"aggs": {
"range_agg": {
"range": {
"field": "field_name",
"ranges": [
{ "to": 10 },
{ "from": 10, "to": 20 },
{ "from": 20 }
]
}
}
}
}
histogram
聚合:用于将字段值按固定的区间进行分组,并统计每个区间的文档数量。
过滤器
用于在查询中应用条件过滤,通常用于 bool
查询的 filter
子句。
term
过滤器:精确匹配字段值。
range
过滤器:根据字段值范围过滤文档。
正排和倒排
在 Elasticsearch 中,排序功能允许你控制文档的检索顺序,这对于根据某些字段(如日期、分数等)对搜索结果进行排序非常重要。排序有两种基本方式:正排序(升序)和倒排序(降序)。
排序的基本概念
- 正排序(升序):将文档按照某个字段的值从小到大进行排列。例如,从最小的日期到最新的日期,或从最低的分数到最高的分数。
- 倒排序(降序):将文档按照某个字段的值从大到小进行排列。例如,从最新的日期到最早的日期,或从最高的分数到最低的分数。
2. 排序的基本语法
在 Elasticsearch 中,你可以通过 sort
参数来指定排序规则。sort
参数支持对一个或多个字段进行排序,并可以指定升序(asc
)或降序(desc
)排序方式。
GET /my_index/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"field1": {
"order": "desc" // 首先按 field1 降序排序
}
},
{
"field2": {
"order": "asc" // 其次按 field2 升序排序
}
}
]
}
正排索引和倒排索引
倒排索引(Inverted Index)和正排索引(Forward Index)是文本检索系统中的两种基本索引结构,用于高效地存储和查询数据。
正排索引:快速获取文档内容,但在进行全文检索时效率较低。
倒排索引:适合全文检索,能够快速定位包含特定词项的文档,但需要额外的存储空间来维护词项和文档 ID 列表。
正排索引
定义: 正排索引是一种传统的数据结构,其中每个文档的 ID 映射到该文档的具体内容。也就是说,它从文档 ID 到文档内容的映射。
结构:
- 文档 ID → 文档内容(字段及其值)
用途: 正排索引主要用于存储和检索文档的原始内容。它的优点是可以快速获取文档的完整内容,但在处理全文检索时不够高效。
示例: 假设有两个文档:
- 文档 1:
{"title": "Introduction to Elasticsearch", "content": "Elasticsearch is a search engine."}
- 文档 2:
{"title": "Advanced Elasticsearch", "content": "Learn advanced features of Elasticsearch."}
正排索引可能看起来像这样:
Document ID 1: {"title": "Introduction to Elasticsearch", "content": "Elasticsearch is a search engine."}
Document ID 2: {"title": "Advanced Elasticsearch", "content": "Learn advanced features of El
倒排索引
定义: 倒排索引是一种用于全文搜索的索引结构,它将词项(单词)映射到包含这些词项的文档 ID 列表。它的结构使得对文档的关键词进行快速检索成为可能。
结构:
- 词项 → 文档 ID 列表(包含该词项的所有文档)
用途: 倒排索引非常适合处理全文检索任务,特别是在需要根据词项查找相关文档时。它的主要优点是可以快速查找包含某个词项的文档。
示例: 对于上述文档,倒排索引可能看起来像这样:
"Elasticsearch" → [1, 2]
"is" → [1]
"a" → [1]
"search" → [1]
"engine" → [1]
"Learn" → [2]
"advanced" → [2]
"features" → [2]
"of" → [2]
工作原理:
- 建立词典:首先构建一个词项词典,列出所有在文档中出现的词项。
- 记录文档 ID:对于每个词项,记录包含该词项的所有文档 ID。
总结
通过以上操作,我们创建了一个存储学生成绩的索引,演示了增删改查的基本操作。这些步骤可以通过 Kibana 的 Dev Tools 或者直接使用命令行中的 curl
命令来执行。如果您有更多需求或问题,可以进一步探索 Elasticsearch 的其他功能,如聚合查询、全文搜索等。
同时,本文也描述了全文检索,es非常擅长全文检索,本文也描述了es常用的操作子,并且对于elasticsearc中正排索引和倒排索引进行了描述。