# 从聚合搜索项目视角入门 ElasticSearch

作者:南侠 (opens new window)编程导航星球 (opens new window) 编号 29240

通过对比MongoDB、分析聚合搜索项目核心流程、分析搜索引擎基本原理、Elastic Stack等思考进一步了解和入门Elasticsearch

在学完聚合搜索项目后,笔者对Elasticsearch(下称ES)的基本语法和应用流程有了较为全面的了解、学习和掌握,同时因为之前了解过MongoDB、搜索引擎的基本原理,因此有了一些思考,如下:

  1. Elastic Stack 这一套技术栈包括的内容?
  2. 做聚合搜索时,可以用ES实现哪些实用功能?
  3. 同样支持倒排索引,对比MongoDB,ES的优势是什么?
  4. 搜索引擎的流程是什么,ES可以在哪个环节进行参与?
  5. 在聚合搜索这个项目中,涉及ES的流程的具体实现使用的技术分别有哪些?

愚以为这些思考,有助于进一步认识ES,并希望通过这些思考,能够对聚合搜索(或搜索引擎)的实现流程,有一个具体实现的方案和思路。以下就是对于以上思考的答案,也希望能对读者有一定启发作用。

# 一、Elastic Stack 这一套技术栈包括的内容

官网:https://www.elastic.co/cn/ 包含了数据的整合 => 提取 => 存储 => 使用,一整套。

Elastic Stack 是一个开源的数据分析平台,主要用于实时搜索、分析和可视化大规模的结构化和非结构化数据。它包含以下主要组件:

  1. Elasticsearch:这是 Elastic Stack 的核心组件,一个分布式的实时搜索和分析引擎。Elasticsearch 负责存储、搜索和分析数据,并提供 RESTful API 以进行数据索引和查询。
  2. Logstash:Logstash 是一个用于数据收集、转换和发送的数据处理管道工具。它可以从多种来源(如日志文件、消息队列、数据库等)收集数据,然后进行过滤、转换和标准化,最后将数据发送到 Elasticsearch 等目标存储或分析系统。
  3. Kibana:Kibana 是 Elastic Stack 的可视化平台,用于分析和可视化 Elasticsearch 中的数据。它提供了丰富的图表、图形和仪表板,用户可以通过 Kibana 轻松地创建定制化的数据可视化和仪表板,并进行数据分析和探索。
  4. Beats:Beats 是一组轻量级的数据收集器,用于收集各种类型的操作数据,并将其发送到 Elasticsearch 或 Logstash 进行处理和存储。Beats 包括多个模块,如 Filebeat 用于收集日志文件、Metricbeat 用于收集系统和服务指标、Packetbeat 用于网络数据分析等。

这些组件共同构成了 Elastic Stack,使用户能够以高效、灵活和可扩展的方式收集、存储、搜索、分析和可视化数据。

# 二、做聚合搜索时,可以通过ES实现哪些实用功能?

# 1. 通过text、keyword字段分别实现模糊查询和精确查询

当在 Elasticsearch 中设置索引的映射(mapping)时,如果字段的类型被定义为 text,Elasticsearch 会默认将这些字段纳入倒排索引中。

**倒排索引(Inverted Index)**是 Elasticsearch 用于实现全文搜索功能的核心数据结构之一。它将每个文档中的所有单词(或者称为词条、术语)映射到包含该单词的文档列表上。这样的索引结构使得 Elasticsearch 能够快速地进行文本搜索。

对于 text 类型的字段,Elasticsearch 会将文本数据分析成单词,然后将这些单词存储在倒排索引中。这样做的好处是,用户可以通过搜索查询中的单词来查找包含这些单词的文档,而不必考虑单词的顺序或大小写等问题。

需要注意的是,对于需要进行精确匹配或排序的字段,通常会将字段类型定义为 keyword 类型,而不是 text 类型。keyword 类型的字段不会被纳入倒排索引中,而是以精确值进行索引,适用于需要进行精确匹配或聚合操作的场景。


其中,关于倒排索引:

当你在搜索引擎中进行一个查询时,比如输入了一个关键词,搜索引擎会迅速地找到所有包含这个关键词的文档。这样的速度是怎么实现的呢?这就是倒排索引发挥作用的地方。

假设有一个包含了大量文档的数据库,每个文档都有一些关键词。倒排索引是一种将这些关键词映射到文档的数据结构,它的原理如下:

  1. 收集关键词:首先,对于每个文档,搜索引擎会分析其内容,将关键词提取出来。这可能包括分词(将文本分成一个个单词)、去除停用词(例如 "the", "a", "an" 等)和其他文本预处理操作。
  2. 建立映射:然后,对于每个关键词,搜索引擎会建立一个映射,将该关键词与包含该关键词的文档列表关联起来。这个过程叫做建立倒排索引。
  3. 搜索过程:当你输入一个查询时,搜索引擎会立即查找包含这个查询关键词的文档列表。这个过程非常迅速,因为搜索引擎只需简单地查找这个关键词在倒排索引中的条目,然后返回与之相关联的文档列表。

倒排索引的优点在于它的查询速度非常快,因为它不需要遍历整个文档集合,而只需查找倒排索引中的条目。此外,倒排索引还支持高级搜索功能,比如短语匹配、布尔搜索等。

举个例子,假设有一个包含了多篇文章的数据库。当你搜索 "Elasticsearch" 时,倒排索引可以立即告诉搜索引擎哪些文章包含了 "Elasticsearch",而不需要搜索引擎逐篇逐句地查找。这样就能极大地加速搜索过程。


同时,倒排索引是一个需要维护的数据结构。在搜索引擎中,当有新的文档被索引、已有文档被修改或删除时,都会触发倒排索引的更新操作。

具体来说,当有新的文档被索引时,搜索引擎会分析文档内容并提取关键词,然后将这些关键词与文档的标识(如文档 ID)建立映射关系,并将这些映射关系添加到倒排索引中。这样就能在搜索时快速找到包含这些关键词的文档。

当已有文档被修改或删除时,搜索引擎也会相应地更新倒排索引。如果修改操作导致文档内容发生变化,那么搜索引擎需要重新分析文档内容,并更新倒排索引中与该文档相关的条目。如果文档被删除,搜索引擎则需要从倒排索引中移除与该文档相关的条目。

倒排索引的维护是搜索引擎索引更新的关键部分,它确保了搜索引擎能够及时准确地响应用户的搜索请求,并保持搜索性能的稳定性。虽然倒排索引的维护会带来一定的计算和存储开销,但这是搜索引擎能够高效工作的基础


在 Elasticsearch 中,每个索引都有自己的倒排索引,因此不同的索引中的同名字段会分别构建不同的倒排索引。所以,如果你有两个不同的索引,它们都包含了同名的 text 类型字段,那么每个索引会分别构建自己的倒排索引表。

当用户按照这个字段进行查询时,Elasticsearch 会在每个索引的倒排索引表中进行搜索,并返回匹配的结果。换句话说,两个不同的索引中的同名字段数据会分别被检索,并且用户会得到包含了这两个索引中相关数据的搜索结果。

如果你希望将两个不同索引中同名字段的数据合并在一起进行搜索,你可以使用 Elasticsearch 提供的多索引搜索功能,或者在查询时指定多个索引。这样 Elasticsearch 就会在多个索引的倒排索引表中进行搜索,并将结果合并返回给用户。


收集关键词阶段,搜索引擎可以使用分词器来对文档内容进行分词处理,以提取出关键词。

对于中文文档而言,常用的分词器包括 IK Analyzer、Jieba 分词器等。这些分词器能够根据中文语言的特点将文本分成一个个单词或词语,并且会考虑到词义、停用词等因素,以提高搜索的准确性和效率。

例如,IK Analyzer 是一个常用的中文分词器,它能够根据中文语法规则将文本分成有意义的词语,同时过滤掉停用词(如 "的"、"了"、"是" 等),从而提高搜索的精确度。

因此,在处理中文文档时,使用合适的分词器对文本进行分词处理是非常重要的,能够有效地提取出关键词,为搜索引擎的后续操作提供准确的数据。


示例表结构(DSL语法)

POST post_v1
{
  "aliases": {
    "post": {}
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "content": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "tags": {
        "type": "keyword"
      },
      "userId": {
        "type": "keyword"
      },
      "createTime": {
        "type": "date"
      },
      "updateTime": {
        "type": "date"
      },
      "isDelete": {
        "type": "keyword"
      }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

# 2. 搜索建议

Elasticsearch 提供了搜索建议(Search Suggest)功能,它能够根据用户输入的搜索查询词,实时地提供搜索建议或自动完成功能,帮助用户更快速地找到他们感兴趣的内容。这个功能通常被用于搜索框下拉列表中,以帮助用户在输入查询时快速获得相关的搜索建议。

在 Elasticsearch 中,搜索建议功能主要通过两种方式实现:

  1. 完全匹配建议(Term Suggester):这种建议是基于用户输入的查询词的拼写或输入错误进行纠正和完全匹配的。Elasticsearch 使用一种称为编辑距离(Edit Distance)的算法来识别和纠正输入中的拼写错误,并提供与纠正后的查询词相匹配的建议。
  2. 上下文建议(Context Suggester):这种建议是根据用户输入的上下文信息(如用户的搜索历史、用户的地理位置、用户的偏好等)来提供与上下文相关的搜索建议。Elasticsearch 可以使用上下文信息来过滤搜索建议,以提供更加个性化和有针对性的搜索建议。

要使用搜索建议功能,通常需要创建一个索引并在索引中定义一个或多个搜索建议器。搜索建议器定义了搜索建议的类型和规则,并且可以根据需求进行配置和调优。一旦搜索建议器被创建,就可以通过 Elasticsearch 提供的搜索建议 API 来获取搜索建议并将其显示在用户界面上。

总的来说,搜索建议功能能够提升用户搜索体验,让用户更加方便快捷地找到他们感兴趣的内容,从而提高了搜索系统的可用性和用户满意度。


当使用 Elasticsearch 的搜索建议功能时,您可以根据不同的需求选择使用完全匹配建议、上下文建议或它们的组合。以下是针对每种情况的示例:

# 2.1. 单独使用完全匹配建议(Term Suggester):

POST /my_index/_search
{
  "suggest": {
    "my_suggestion": {
      "text": "搜索建议示例", 
      "term": {
        "field": "suggest_field" 
      }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11

在这个示例中,我们使用了 "term" 类型的建议器,表示要执行的是基于完全匹配的建议。这会返回与用户输入的查询词相匹配的建议结果,用于纠正用户输入的拼写错误或提供自动完成功能。

# 2.2. 单独使用上下文建议(Context Suggester):

POST /my_index/_search
{
  "suggest": {
    "my_suggestion": {
      "text": "搜索建议示例", 
      "context": {
        "location": {
          "lat": 40.73,
          "lon": -74.1
        }
      },
      "completion": {
        "field": "suggest_field" 
      }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

在这个示例中,我们在搜索建议器中同时使用了 "completion" 类型和 "context" 参数,表示要执行的是基于上下文的建议。通过配置不同的上下文参数,例如用户的地理位置、搜索历史等,可以过滤和定制搜索建议的结果,使其更加个性化和有针对性。

在 Elasticsearch 中,上下文建议(Context Suggester)允许您根据用户的上下文信息来定制搜索建议的结果。其中,"context" 参数用于指定上下文信息,以过滤和定制搜索建议的结果。

在您提供的示例中,"location" 上下文参数指定了用户的地理位置信息,包括经纬度。这样,您可以根据用户的地理位置来调整搜索建议的结果,以确保返回的建议与用户所在位置相关联。

举例来说,假设您正在为一个手机应用开发地理位置服务,用户正在输入搜索查询词 "餐厅"。通过提供用户的地理位置信息,您可以定制搜索建议的结果,使其返回附近的餐厅名称或地址,从而帮助用户更方便地找到附近的餐厅。

总的来说,"context" 参数允许您根据用户的上下文信息来定制搜索建议的结果,以提供更加个性化和有针对性的搜索体验。

# 2.3. 综合使用完全匹配和上下文建议:

POST /my_index/_search
{
  "suggest": {
    "my_suggestion": {
      "text": "搜索建议示例", 
      "term": {
        "field": "suggest_field" 
      },
      "context": {
        "location": {
          "lat": 40.73,
          "lon": -74.1
        }
      }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

在这个示例中,我们在搜索建议器中同时使用了完全匹配建议和上下文建议。这意味着搜索建议结果将同时考虑用户输入的查询词以及用户的上下文信息,以提供更加准确和有针对性的搜索建议。

# 3. 搜索高亮

Elasticsearch 的搜索高亮功能允许您在搜索结果中突出显示匹配搜索条件的部分,以提高用户的搜索体验和结果的可读性。当用户进行全文搜索时,高亮功能可以使匹配的关键词在搜索结果中更加显眼,帮助用户快速定位到相关内容。

搜索高亮功能的实现原理是在搜索结果中将匹配搜索条件的文本片段用指定的标记进行包裹,例如 <em> 标签,以标识出这部分文本是搜索条件的匹配结果。这样,在搜索结果中就可以直观地看到哪些部分是与搜索条件匹配的,从而让用户更容易理解搜索结果。

以下是一个示例,演示如何在 Elasticsearch 中使用搜索高亮功能:

POST /my_index/_search
{
  "query": {
    "match": {
      "content": "关键词"
    }
  },
  "highlight": {
    "fields": {
      "content": {}
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

在这个示例中:

  • "query" 部分指定了要执行的搜索查询,这里使用了简单的匹配查询,匹配字段 "content" 中包含 "关键词" 的文档。
  • "highlight" 部分指定了要对哪些字段进行高亮处理,这里指定了字段 "content"。
  • 通过执行这个查询,Elasticsearch 将会返回搜索结果,并将匹配 "关键词" 的部分用指定的标记进行高亮显示。

您可以通过配置不同的高亮参数,例如指定高亮标记的类型、定制高亮标记的样式等,以满足不同的需求和场景。

总的来说,搜索高亮功能是 Elasticsearch 中一个非常实用的功能,能够提高搜索结果的可读性和用户体验,帮助用户更加快速地找到他们感兴趣的内容。


例如,可以指定其他标签作为搜索结果高亮的标记,而不仅限于 <em> 标签。在 Elasticsearch 中,您可以通过设置 "pre_tags""post_tags" 参数来指定高亮的起始标记和结束标记。

以下是一个示例,演示如何在 Elasticsearch 中使用自定义标记进行搜索结果高亮:

POST /my_index/_search
{
  "query": {
    "match": {
      "content": "关键词"
    }
  },
  "highlight": {
    "pre_tags": ["<strong>"],
    "post_tags": ["</strong>"],
    "fields": {
      "content": {}
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

在这个示例中,我们使用了 <strong> 标签作为高亮的起始标记,</strong> 标签作为高亮的结束标记。这样,在搜索结果中匹配到的文本片段就会被 <strong></strong> 标签包裹起来,以标识出匹配的部分。

可以根据需要自定义任何标记来标识搜索结果的高亮部分,以适应您的应用场景和样式需求。

# 三、同样支持倒排索引,对比MongoDB,ES的优势是什么?

Elasticsearch(ES)和MongoDB都是流行的数据存储和检索解决方案,但它们在设计目标、特点和适用场景上有所不同。以下是 Elasticsearch 相对于 MongoDB 的一些优势:

  1. 全文搜索功能: Elasticsearch 是一个专门用于全文搜索和分析的搜索引擎,具有强大的全文搜索和分析功能,支持复杂的搜索查询、聚合分析和搜索建议等功能。相比之下,MongoDB 虽然也支持文本搜索,但其功能相对较弱。
  2. 分布式性能和可扩展性: Elasticsearch 是一个分布式系统,具有良好的水平扩展性和高可用性。它可以轻松地处理大规模数据集和高并发请求,并能够通过添加更多的节点来实现横向扩展。MongoDB 也支持分片和副本集等方式来实现水平扩展,但相比之下,Elasticsearch 在分布式性能和扩展性方面更为出色。
  3. 实时索引和搜索: Elasticsearch 提供了近实时(Near Real-Time)的索引和搜索功能,即当新的文档被索引时,它们几乎立即就可以被搜索到。这使得 Elasticsearch 在需要实时索引和搜索的应用场景下具有明显的优势。MongoDB 也支持实时索引和搜索,但相比之下,Elasticsearch 的实时性能更好。
  4. 复杂的聚合和分析: Elasticsearch 提供了丰富的聚合和分析功能,可以对大规模数据集进行复杂的数据分析和聚合操作。它支持多种聚合操作,如分组聚合、统计聚合、日期直方图聚合等,能够快速地对数据进行深入分析。MongoDB 也支持聚合框架来执行复杂的数据分析,但 Elasticsearch 在聚合和分析功能方面更加强大和灵活。
  5. 全文检索与结构化数据的融合: Elasticsearch 可以同时处理全文检索和结构化数据,使得开发人员可以在同一个平台上完成文本搜索和结构化数据的存储和检索操作。相比之下,MongoDB 更偏向于结构化数据的存储和查询,全文搜索功能相对有限。

综上所述,Elasticsearch 在全文搜索、分布式性能、实时索引和搜索、复杂的聚合分析等方面具有明显的优势,特别适用于需要高性能全文搜索和复杂数据分析的应用场景。而 MongoDB 则更适用于对结构化数据进行存储和查询的应用场景。

# 1. 应用场景

MongoDB 和 Elasticsearch(ES)都是强大的数据存储和检索工具,但它们的设计目标和特点不同,适用于不同的应用场景。以下是它们各自的主要应用场景:

# 1.1. MongoDB 的主要应用场景

  1. 大部分操作是基于数据的 CRUD 操作: MongoDB 适合于大部分操作是基于数据的增删改查操作的应用场景,例如 Web 应用的后端数据库、内容管理系统(CMS)、博客平台等。
  2. 需要灵活的数据模型: MongoDB 是一种 NoSQL 数据库,支持灵活的数据模型,能够存储半结构化或非结构化的数据,因此适用于需要频繁更改数据模式的应用场景。
  3. 需要高性能和可扩展性: MongoDB 具有良好的性能和可扩展性,能够轻松地处理大规模数据和高并发请求。它支持分片和副本集等方式来实现水平扩展,因此适用于需要高性能和可扩展性的应用场景。
  4. 实时数据分析和报表生成: MongoDB 支持丰富的聚合操作和数据分析功能,能够快速地对数据进行聚合和分析,因此适用于实时数据分析和报表生成的应用场景。

# 1.2. Elasticsearch 的主要应用场景

  1. 全文搜索和分析: Elasticsearch 是一个专门用于全文搜索和分析的搜索引擎,适用于需要高效全文搜索和分析功能的应用场景,例如搜索引擎、日志分析、文档管理系统等。
  2. 需要复杂的搜索查询和聚合分析: Elasticsearch 提供了丰富的查询操作和聚合操作,能够执行复杂的搜索查询和数据分析,因此适用于需要复杂搜索查询和聚合分析功能的应用场景。
  3. 需要实时索引和搜索: Elasticsearch 提供近实时的索引和搜索功能,能够快速地索引新的文档并进行搜索,因此适用于需要实时索引和搜索功能的应用场景,例如实时日志分析、监控系统等。
  4. 需要高性能和可扩展性: Elasticsearch 具有良好的性能和可扩展性,能够轻松地处理大规模数据和高并发请求,适用于需要高性能和可扩展性的应用场景。

总的来说,MongoDB 适用于大部分操作是基于数据的 CRUD 操作、需要灵活的数据模型和需要高性能和可扩展性的应用场景,而 Elasticsearch 适用于需要高效全文搜索和分析功能、复杂的搜索查询和聚合分析功能以及需要实时索引和搜索功能的应用场景。

# 2. 全文匹配

当涉及到全文搜索和倒排索引功能时,MongoDB 和 Elasticsearch(ES)有着不同的实现方式和特点。下面将分别介绍它们的倒排索引全文匹配功能,然后进行详细比较:

# 2.1. MongoDB 的全文匹配功能

MongoDB 的全文搜索功能通过全文索引实现,它使用文本索引来支持文本字段的全文搜索。MongoDB 的全文索引支持文本查询操作,如 $text 查询操作符和 $search 查询操作符。您可以在文本字段上创建文本索引,并使用 $text 查询操作符来执行全文搜索查询。

下面是 MongoDB 全文搜索的示例:

db.articles.createIndex({ content: "text" });

// 查询包含关键词 "Elasticsearch" 的文档
db.articles.find({ $text: { $search: "Elasticsearch" } });
1
2
3
4

# 2.2. Elasticsearch 的全文匹配功能

Elasticsearch 是专门用于全文搜索和分析的搜索引擎,它使用倒排索引和分析器来实现全文搜索功能。在 Elasticsearch 中,您可以针对文本字段定义自定义的分析器(Analyzer),以便对文本进行分词和处理,并使用倒排索引来存储和快速检索文本数据。

下面是 Elasticsearch 全文搜索的示例:

POST /articles/_search
{
  "query": {
    "match": {
      "content": "Elasticsearch"
    }
  }
}
1
2
3
4
5
6
7
8

# 2.3. MongoDB 和 Elasticsearch 的全文搜索功能比较

  1. 实现方式: MongoDB 使用全文索引来支持全文搜索,而 Elasticsearch 则使用倒排索引和分析器来实现全文搜索。
  2. 功能丰富程度: Elasticsearch 的全文搜索功能更加丰富和灵活,支持更多的查询类型、聚合操作和搜索建议功能等。MongoDB 的全文搜索功能相对较简单,支持的操作和功能较少。
  3. 性能和扩展性: Elasticsearch 在全文搜索性能和扩展性方面更具优势,特别是在大规模数据集和高并发请求的场景下,其性能和扩展性表现更好。
  4. 实时性: Elasticsearch 提供近实时的索引和搜索功能,能够快速地索引新的文档并进行搜索,而 MongoDB 的全文索引需要在后台进行后台构建和维护,可能不如 Elasticsearch 实时。

综上所述,虽然 MongoDB 也提供了全文搜索功能,但相比之下,Elasticsearch 更适用于需要强大全文搜索功能的应用场景,特别是在需要高性能、实时性和灵活性的场景下,Elasticsearch 是更好的选择。

# 3. 全文搜索

详细地对比一下 MongoDB 和 Elasticsearch 的全文搜索功能,包括是否支持分词、定制化插件等方面的细节。

# 3.1. MongoDB 的全文搜索功能

  1. 支持分词: MongoDB 的全文搜索功能基于文本索引实现,它会在创建文本索引时将文本字段的内容进行分词处理。MongoDB 支持基于分词后的词语进行查询匹配。
  2. 分词器: MongoDB 内置了一个简单的分词器,用于对文本进行基本的分词处理。然而,MongoDB 不支持像 Elasticsearch 那样灵活地定制分词器或使用第三方分词器。

# 3.2. Elasticsearch 的全文搜索功能

  1. 支持分词: Elasticsearch 使用分词器(Analyzer)对文本进行分词处理,可以将文本字段分割成独立的词语进行索引和搜索。Elasticsearch 支持多种内置的分词器,例如 Standard 分词器、Simple 分词器、Whitespace 分词器等。
  2. 定制化插件: Elasticsearch 允许用户通过定制化插件来扩展和定制分词器。用户可以根据自己的需求使用自定义分词器,例如 IK Analyzer、Smart Chinese Analysis 等,来适应不同语言的分词需求。
  3. 支持多语言: Elasticsearch 支持多种语言的分词处理,包括中文、英文、法文、德文等。用户可以根据需要选择合适的分词器进行配置。
  4. 复杂查询: Elasticsearch 提供了丰富的查询操作和查询语法,支持复杂的全文搜索和过滤条件。用户可以使用各种查询操作符和组合条件来执行复杂的全文搜索查询。

# 3.3. 比较

  • 分词支持: Elasticsearch 提供了更加灵活和强大的分词支持,允许用户使用各种内置和定制化分词器来满足不同语言和需求的分词需求。
  • 定制化插件: Elasticsearch 允许用户使用定制化插件来扩展和定制分词器,使得用户能够根据具体需求选择合适的分词器。
  • 复杂性和灵活性: Elasticsearch 在全文搜索功能的复杂性和灵活性方面更具优势,支持更多的查询操作、聚合操作和搜索建议功能等。

总的来说,虽然 MongoDB 也提供了基本的全文搜索功能,但相比之下,Elasticsearch 在分词支持、定制化插件和搜索功能的复杂性和灵活性方面更具优势,特别适用于需要强大全文搜索功能的应用场景。

# 四、搜索引擎的流程是什么,ES可以在哪个环节进行参与?

# 1. 搜索引擎

有关搜索引擎可参考此文章:https://mp.weixin.qq.com/s/zn-SvUN5E4WWQhs88ienzQ

# 1.1. 第 1 步 - 抓取

网络爬虫会在互联网上扫描网页。它们跟踪从一个页面到另一个页面的 URL 链接,并将 URL 存储在 URL 存储器中。爬虫会发现新的内容,包括网页、图片、视频和文件。

# 1.2. 第 2 步 - 编制索引

网页被抓取后,搜索引擎会对网页进行解析,并将网页上的内容编入索引数据库。对内容进行分析和分类。例如,评估关键字、网站质量、内容新鲜度和许多其他因素,以了解网页的内容。

# 1.3. 第 3 步 - 排名

搜索引擎使用复杂的算法来决定搜索结果的顺序。这些算法会考虑各种因素,包括关键词、页面相关性、内容质量、用户参与度、页面加载速度等。有些搜索引擎还会根据用户过去的搜索历史、位置、设备和其他个人因素对搜索结果进行个性化处理。

# 1.4. 第 4 步 - 查询

当用户执行搜索时,搜索引擎会筛选其索引,以提供最相关的结果。

# 2. ES的作用

在第 2 步 - 编制索引中,ES可以作为索引数据库,在后续第4步用户执行搜索时,提供搜索服务。

在第 3 步 - 排名中,ES的查询结果中的相关度得分可作为最终排名的参考之一。

具体而言,Elasticsearch 的查询结果包含每个文档的相关度得分(score),用于衡量文档与查询的匹配程度。得分越高表示文档与查询的匹配程度越高,排名越靠前。

下面是一个简单的示例,说明 Elasticsearch 查询结果中的得分字段:

假设我们有一个名为 "articles" 的索引,其中存储了一些文章数据,我们想要搜索标题(title)字段中包含关键词 "Elasticsearch" 的文档,并获取其相关度得分。我们可以使用如下的查询:

POST /articles/_search
{
  "query": {
    "match": {
      "title": "Elasticsearch"
    }
  }
}
1
2
3
4
5
6
7
8

查询结果中会包含每个文档的相关度得分,例如:

{
  "took": 10,
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 0.6931472,  // 最高得分
    "hits": [
      {
        "_index": "articles",
        "_type": "_doc",
        "_id": "1",
        "_score": 0.6931472,  // 文档的得分
        "_source": {
          "title": "Introduction to Elasticsearch"
        }
      },
      {
        "_index": "articles",
        "_type": "_doc",
        "_id": "2",
        "_score": 0.2876821,  // 文档的得分
        "_source": {
          "title": "Getting Started with Elasticsearch"
        }
      }
    ]
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

在上面的查询结果中,每个文档都有一个 "_score" 字段,表示其相关度得分。得分最高的文档排名最靠前。


在 Elasticsearch 中,文档的相关度得分(score)是根据文档与查询的匹配程度来计算的,得分越高表示文档与查询的匹配程度越高。Elasticsearch 使用 TF-IDF 算法和向量空间模型(Vector Space Model)来计算文档的相关度得分。

下面是相关度得分的计算方式和标准:

  1. TF(Term Frequency,词频): 计算查询词在文档中出现的频率,即查询词在文档中出现的次数。词频越高,得分越高。
  2. IDF(Inverse Document Frequency,逆文档频率): 计算查询词在整个索引中出现的频率,即查询词在多少个文档中出现过。逆文档频率越低,表示查询词越常见,相关度得分越低。
  3. 字段长度归一化: 对于较长的字段,文档的相关度得分会被字段长度归一化,以避免较长的字段对相关度得分的影响过大。
  4. 字段权重调整: Elasticsearch 支持对不同字段设置不同的权重(boost),可以通过字段权重来调整字段在计算得分时的重要性。
  5. BM25 算法(Best Matching 25): Elasticsearch 默认使用 BM25 算法来计算文档的相关度得分,BM25 算法是一种改进的 TF-IDF 算法,考虑了词频和逆文档频率之间的平衡,并且对较长的字段有较好的适应性。

总的来说,Elasticsearch 使用复杂的算法和模型来计算文档的相关度得分,以确保搜索结果的准确性和相关性。得分越高的文档越接近查询的意图,排名越靠前。

# 五、在聚合搜索这个项目中,涉及ES的流程的具体实现使用的技术分别有哪些?

# 1. 数据抓取

在聚合搜索这个项目中,数据的类型主要有两种:数据库表数据和网络图片数据(必应)。因此,对应的数据抓取方式也有两种:

  1. 数据库数据:使用ChatGPT来生成insert的SQL语句
  2. 网络图片数据:使用爬虫技术,如java使用jsoup库,python使用bs4库。

# 2. 表结构设置和监控

表结构设计基本是使用ES的DSL语法,设置Mapping结构:

POST post_v1
{
  "aliases": {
    "post": {}
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "content": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "tags": {
        "type": "keyword"
      },
      "userId": {
        "type": "keyword"
      },
      "createTime": {
        "type": "date"
      },
      "updateTime": {
        "type": "date"
      },
      "isDelete": {
        "type": "keyword"
      }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

执行DSL语句和可视化es数据看板,则使用Kibana。

# 3. 数据同步

一般情况下,如果做查询搜索功能,使用 ES 来模糊搜索,但是数据是存放在数据库 MySQL 里的,所以说我们需要把 MySQL 中的数据和 ES 进行同步,保证数据一致(以 MySQL 为主)。 MySQL => ES (单向) 首次安装完 ES,把 MySQL 数据全量同步到 ES 里,写一个单次脚本 4 种方式,全量同步(首次)+ 增量同步(新数据):

  1. 定时任务,比如 1 分钟 1 次,找到 MySQL 中过去几分钟内(至少是定时周期的 2 倍)发生改变的数据,然后更新到 ES。 优点:简单易懂、占用资源少、不用引入第三方中间件 缺点:有时间差 应用场景:数据短时间内不同步影响不大、或者数据几乎不发生修改
  2. 双写:写数据的时候,必须也去写 ES;更新删除数据库同理。(事务:建议先保证 MySQL 写成功,如果 ES 写失败了,可以通过定时任务 + 日志 + 告警进行检测和修复(补偿))
  3. Logstash 数据同步管道(一般要配合 kafka 消息队列 + beats 采集器)
  4. Canal 监听 MySQL Binlog,实时同步

# 4. 客户端调用和查询(Java)

第一种方式:ElasticsearchRepository<PostEsDTO, Long>,默认提供了简单的增删改查,多用于可预期的、相对没那么复杂的查询、自定义查询,返回结果相对简单直接。 接口代码:

public interface CrudRepository<T, ID> extends Repository<T, ID> {
    <S extends T> S save(S entity);

    <S extends T> Iterable<S> saveAll(Iterable<S> entities);

    Optional<T> findById(ID id);

    boolean existsById(ID id);

    Iterable<T> findAll();

    Iterable<T> findAllById(Iterable<ID> ids);

    long count();

    void deleteById(ID id);

    void delete(T entity);

    void deleteAllById(Iterable<? extends ID> ids);

    void deleteAll(Iterable<? extends T> entities);

    void deleteAll();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

ES 中,_开头的字段表示系统默认字段,比如 _id,如果系统不指定,会自动生成。但是不会在 _source 字段中补充 id 的值,所以建议大家手动指定。 支持根据方法名自动生成方法,比如:

List<PostEsDTO> findByTitle(String title);
1

第二种方式:Spring 默认给我们提供的操作 es 的客户端对象 ElasticsearchRestTemplate,也提供了增删改查,它的增删改查更灵活,适用于更复杂的操作,返回结果更完整,但需要自己解析。 对于复杂的查询,建议用第二种方式。 三个步骤:

第二种方式:Spring 默认给我们提供的操作 es 的客户端对象 ElasticsearchRestTemplate,也提供了增删改查,它的增删改查更灵活,适用于更复杂的操作,返回结果更完整,但需要自己解析。 对于复杂的查询,建议用第二种方式。 三个步骤:

  1. 取参数
  2. 把参数组合为 ES 支持的搜索条件
  3. 从返回值中取结果

# 5. 压力测试

官方文档:https://jmeter.apache.org/ 找到 jar 包:apache-jmeter-5.5\apache-jmeter-5.5\bin\ApacheJMeter.jar 启动 配置线程组 => 请求头 => 默认请求 => 单个请求 => 响应断言 => 聚合报告 / 结果树

99%分位:99%的用户都在这个响应时间内 吞吐量:每秒处理的请求数 qps


压力测试(Stress Testing)是一种评估系统在负载增加的情况下性能表现的方法。进行压力测试的主要目的是发现系统的性能瓶颈、识别系统的性能极限、验证系统是否能够在预期的负载下正常工作,并评估系统的稳定性和可靠性。

以下是压力测试的一些重要意义:

  1. 发现性能瓶颈: 通过模拟高负载情况,可以发现系统在哪些方面存在性能瓶颈,例如数据库响应速度、网络带宽、CPU 使用率等。这有助于优化系统的性能,提高系统的吞吐量和响应速度。
  2. 验证系统是否满足需求: 压力测试可以验证系统是否能够在预期的负载下正常工作,并且在高负载情况下仍然保持良好的性能。这有助于确定系统是否满足业务需求,以及确定是否需要进行性能优化或增加资源。
  3. 评估系统的稳定性: 通过模拟高负载情况,可以测试系统在极端条件下的稳定性。如果系统在高负载情况下出现异常或崩溃,这可能表明系统存在潜在的稳定性问题,需要进一步调查和修复。
  4. 预测系统的扩展性: 通过压力测试,可以评估系统在不同负载下的性能表现,并预测系统在未来负载增加时的表现。这有助于规划系统的扩展性,确定何时需要增加更多的资源或进行系统升级。
  5. 评估系统的容错性: 压力测试还可以评估系统在负载增加或出现异常情况下的容错能力。这有助于确定系统在面对异常情况时是否能够保持正常运行,并且能够有效地处理错误和恢复正常状态。

综上所述,压力测试对于评估系统的性能、稳定性、扩展性和容错性具有重要意义,能够帮助开发团队和运维团队更好地理解系统的性能特征,优化系统的性能,提高系统的可靠性和稳定性。


下面是一些其他常用的压力测试指标:

  1. 每秒请求数(Queries Per Second,QPS): 指系统在单位时间内处理的查询请求数量,通常以每秒请求数(Queries Per Second,QPS)为单位。QPS 是评估系统性能的重要指标之一,也是吞吐量的一种度量方式。
  2. 响应时间分位数(Response Time Percentiles): 包括平均响应时间、中位数响应时间(50th percentile)、90th percentile、95th percentile 等,用于描述系统的响应时间分布情况。例如,95th percentile 表示 95% 的请求在该时间内完成。
  3. 峰值负载(Peak Load): 指系统在压力测试期间达到的最大负载水平,通常用于评估系统在极端条件下的性能表现和稳定性。
  4. 持续时间(Duration): 指压力测试持续运行的时间长度,通常以分钟或小时为单位。持续时间越长,能够评估系统长期运行时的性能表现和稳定性。
  5. 启动时间(Startup Time): 指系统从启动到完全响应请求所花费的时间,通常用于评估系统的启动性能和初始化时间。
  6. 资源消耗(Resource Consumption): 包括 CPU 使用率、内存消耗、网络带宽等系统资源的消耗情况。资源消耗反映了系统在不同负载下的资源利用情况,可以用于优化系统配置和资源调整。
  7. 错误类型和频率(Error Types and Frequencies): 包括系统返回的错误类型和错误频率。通过分析错误类型和频率,可以识别系统存在的问题并采取相应的措施进行修复。

综上所述,以上指标是常用于评估系统性能和稳定性的重要指标,可以帮助开发团队和运维团队更好地了解系统的性能特征,优化系统性能,并确保系统能够在不同负载下正常工作。

最近更新: 2/20/2024, 3:37:19 PM
编程导航   |