Elasticsearch基本概念及使用

Elasticsearch 是一个开源的、分布式的全文搜索和分析引擎,基于 Apache Lucene 构建。它提供了快速的搜索能力,支持大规模的数据分析,广泛应用于日志分析、全文搜索、监控系统和商业智能等领域。ES操作指令是基于restAPI构建,也就是说,操作ES需要向其服务端口发送http请求,ES会根据请求类型、uri、请求参数等,决定具体行为。

文章中涉及的指令操作,都会在Kibana提供的devtool中执行,可以查看我的文章Elasticsearch集群及Kibana部署流程,对其进行部署后学习。

1. 存储数据结构

ES通过索引定义存储数据的结构,什么是索引呢?我们可以类型数据库的表,索引和数据库的表极为类似,可以存储一种数据类型的数据。在6版本及之前,索引可以存储多种数据类型的数据,更像是数据库,而7版本及之后,索引只可以存储一种数据结构。

ES通过json类型存储数据,索引本质上就是一种json结构,其中包含了多个属性,其中mapping属性中定义了索引中存储类型的结构,我们称其为映射,映射就可以类比为数据库的表结构,其中定义了索引可以存储那种结构的json,以及作为搜索引擎时,其属性的搜索规则等。

除了映射外,索引中还包含setting属性,其定义了当前索引的一切特性,甚至集群表现,如果当前索引的集群分片数,副本数(ES的集群分片可以针对索引设置,大大提高了优化性能的可操作性)等索引特性。

除此之外,还包括aliaes(索引别名),完整属性如下:

{"settings": {// 索引的基础配置部分"number_of_shards": 1, // 主分片数量,决定索引的水平扩展性"number_of_replicas": 1, // 每个主分片的副本数,提升数据冗余性和查询性能"refresh_interval": "1s", // 刷新间隔时间,默认 1 秒。数据可见性延迟的控制参数"max_result_window": 10000, // 查询分页的最大窗口大小,默认 10000"max_inner_result_window": 100, // 嵌套分页的最大窗口大小,控制内嵌对象的分页深度"max_rescore_window": 10000, // 重新评分窗口的最大值"max_docvalue_fields_search": 100, // 查询中允许的 doc_value 字段数量上限,避免性能问题"max_script_fields": 32, // 查询中允许的脚本字段最大数量"max_ngram_diff": 1, // ngram 分析器的最小和最大长度之差,影响文本分析的粒度"max_shingle_diff": 3, // shingle 分析器的最小和最大长度之差,影响分词的组合方式"analysis": {// 定义分析器、字符过滤器、词汇过滤器等分析组件"analyzer": {"default": {"type": "standard" // 默认使用标准分词器,适合通用文本分词},"custom_analyzer": {"type": "custom","tokenizer": "whitespace", // 自定义分词器,使用空白分词"filter": ["lowercase"] // 词汇过滤器,转换为小写字母}}},"index.lifecycle.name": "my_policy", // 生命周期策略名称,自动管理索引的生命周期"index.lifecycle.rollover_alias": "my_alias", // 用于自动 rollover 的别名,适合日志索引管理"routing_partition_size": 1, // 路由分区大小,影响数据路由的灵活性"codec": "best_compression", // 压缩算法,可选 `best_compression` 提高存储效率"translog.durability": "request", // 事务日志的持久性,`request` 表示每次请求刷盘"priority": 1, // 索引优先级,适用于恢复时控制恢复顺序"queries.cache.enabled": true // 查询缓存开关,提升重复查询性能},"mappings": {// 索引的字段映射配置"dynamic": "strict", // 动态映射设置,`strict` 表示严格模式,禁止未知字段"date_detection": true, // 自动日期检测,启用时会自动识别日期字段"numeric_detection": true, // 自动数值检测,启用时会自动识别整数和浮点数"dynamic_date_formats": ["yyyy-MM-dd"], // 定义动态日期格式,用于日期类型自动识别"properties": {"example_field": {"type": "text",                // 字段的数据类型,如 text、keyword、integer、date 等"analyzer": "standard",         // 指定索引时的分析器"search_analyzer": "whitespace",// 指定搜索时的,与 analyzer 可以不同"boost": 1.0,                   // 相关性评分的权重,值越高权重越大"index": true,                  // 是否对该字段建立索引,默认 true"store": false,                 // 是否将字段单独存储在 _source 外部"doc_values": true,             // 启用或禁用 doc_values,适用于排序、聚合"norms": true,                  // 控制是否启用字段的归一化信息,用于相关性评分"similarity": "BM25",           // 设置相似性算法,默认使用 BM25,可选 classic 等"null_value": "NULL",           // 当字段为空时的默认值"ignore_above": 256,            // 忽略超过指定长度的字符串,适用于 keyword 类型"position_increment_gap": 100,  // 控制数组中元素的短语查询间隔"index_options": "positions",   // 控制索引选项,如 docs, freqs, positions"term_vector": "yes",           // 存储词条向量信息,用于高亮显示等"coerce": true,                 // 强制将非预期类型转换为指定类型,适用于数值类型"copy_to": "another_field",     // 将字段内容复制到另一个字段,用于合并搜索"eager_global_ordinals": false, // 提前加载全局排序,适用于高频使用的 keyword 字段"scaling_factor": 100,          // 用于存储浮点数时将其转换为 long 类型的倍率"format": "yyyy-MM-dd",         // 日期格式,用于 date 类型字段的格式定义"fields": {                     // 定义多字段结构,支持多个索引方式"keyword": {"type": "keyword","ignore_above": 256}},"enabled": true,                // 是否启用该字段,适用于 object 类型字段"dynamic": "strict",            // 控制动态映射,strict 表示未知字段会报错"time_series_dimension": true,  // 是否将字段设为时间序列维度,适用于时序数据"meta": {                       // 字段的元数据,用于附加描述信息"description": "Example field for documentation purposes."},"split_queries_on_whitespace": false // 用于 text 类型,控制查询是否按空格分词}}"enabled": true // 启用或禁用整个索引映射,`false` 会忽略整个映射},"aliases": {// 索引的别名部分"my_alias": {}, // 简单别名,直接指向索引"filtered_alias": {// 带筛选条件的别名,适用于部分查询场景"filter": {"term": { "active": true } // 仅匹配 active 为 true 的文档},"routing": "1" // 路由设置,控制查询或写入操作的路由方式}}
}

这就是一个非常完整的一个索引,当然其中绝大部份属性,我们都使用不到。

数据类型

Elasticsearch(ES)支持多种数据类型,但部分数据类型同常见语言中的不一致。以下是 ES 中常用的数据类型及其详细说明(不建议记住,大部分用不上):

1. 核心基础类型
  • text:适用于全文搜索的文本数据类型。通常用于长文本字段,如产品描述、文章内容等。text 类型字段会进行分词和倒排索引,支持全文搜索。
  • keyword:适用于精确匹配的文本数据。keyword 类型字段不分词,用于存储不需要分析的字符串,如用户名、标签等。适合排序、聚合和过滤。
  • integer:32 位整数类型,用于存储整型数据。适用于数值范围在 ±2,147,483,647 的数据。
  • long:64 位整数类型,用于存储更大范围的整型数据,数值范围在 ±9,223,372,036,854,775,807。
  • float:32 位浮点数类型,适合存储带有小数的数值,精度较低。
  • double:64 位浮点数类型,精度更高,适合存储高精度的数值数据。
  • boolean:布尔类型,用于存储 truefalse 值。
  • date:用于存储日期数据,可以支持多种日期格式(如 yyyy-MM-dd),也可以存储时间戳(毫秒或秒)。支持日期范围查询。
  • binary:用于存储二进制数据(Base64 编码格式)。通常用于存储图片、文件等非结构化数据,不支持搜索。
2. 复合类型
  • object:用于存储 JSON 对象。object 类型字段可以包含子字段,适合嵌套数据结构。注意:object 类型的子字段会被展开并作为顶级字段索引。
  • nested:嵌套对象类型,用于存储数组中的 JSON 对象。与 object 不同,nested 类型会为数组中的每个对象单独创建一个索引,支持更复杂的嵌套查询。
3. 专用类型
  • geo_point:用于存储地理坐标点(经纬度),支持地理位置的距离计算和位置范围查询。常用于地理位置检索。
  • geo_shape:用于存储复杂的地理形状,如多边形、线条等。适合更高级的地理空间计算,比如区域包含、相交等查询。
  • ip:用于存储 IP 地址(IPv4 和 IPv6),支持范围查询和 IP 地址过滤。
  • range:用于存储一个范围,支持以下几种范围类型:
    • integer_range:整型范围。
    • float_range:浮点数范围。
    • long_range:长整型范围。
    • double_range:双精度浮点数范围。
    • date_range:日期范围,适合时间段查询。
4. 专门的数据类型(Elasticsearch 7.10 引入)
  • alias:字段别名,指向索引中现有字段的引用。用于访问实际字段的数据或改变字段名称,而不需要复制字段内容。
  • dense_vectorsparse_vector:用于存储向量数据,通常用于机器学习和相似性计算。
  • rank_featurerank_features:用于存储特征值,用于机器学习模型的排序字段。

操作指令

对于索引结构中的属性进行操作或执行ES提供的一些指令时,通常需要在前面加一个 _ ,而我们自己定义的属性则不需要

1.添加索引

我们可以通过发送get请求的方式添加索引,具体如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2. 查询索引

查询索引需要通过get请求加索引名称,具体如下:

在这里插入图片描述

3. 查询全部索引

通过get请求加_cat/indices?v的uri的形式,查询全部索引,具体如下

_cat不仅仅是查询所有索引的作用,他的主要作用是查询当前ES集群的元数据信息。

在这里插入图片描述

其中可以看到我们刚刚创建的索引

4. 查询当前索引是否存在

我们可以通过Head请求查询索引是否存在,具体如下

在这里插入图片描述

5. 修改索引属性(mapping,setting,alias)

在上文我们已经说过,当修改索引属性时,需要在属性前加上一个 _ ,所以我们可以通过put请求,加上/索引名/_索引属性的形式,进行修改,具体如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注:这种修改操作,对于原来没有的属性会进行新增,而对于已经有的属性则会修改,不过索引中并非所有属性都能够修改,如果修改不能修改的属性则会报错

6. 删除索引

通过delete请求,可以删除索引,具体如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

7. 索引批处理

我们还可以通过_mget和_bulk对索引进行批处理,实例如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图中docs是一个数组可以传入多个条件,并且以其他任何属性为条件

_mget用于批量查询,而剩下的增删改则是全权有bulk负责
在这里插入图片描述

除了删除外,其他的都是第一行是操作及搜索条件,第二行是新数据。

index和create都是插入数据,不同的是index对于已经存在的数据会进行覆盖,而create会报错。

2. 文档

索引中的属性定义了存储数据的结构,及索引的特性,而真实的数据则存储在索引所对应的文档中,一次文档查询的结果如下:

{"took": 5, // 查询耗时,单位为毫秒,表示从发送请求到获得结果的时间"timed_out": false, // 是否超时,false 表示查询在规定时间内完成"_shards": { // 与查询相关的分片统计信息"total": 5, // 查询涉及的分片总数"successful": 5, // 成功响应的分片数量"skipped": 0, // 被跳过的分片数量(例如,索引为空时的分片可能被跳过)"failed": 0 // 查询失败的分片数量},"hits": { // 匹配的文档集合"total": { // 匹配的文档总数"value": 2, // 查询条件下的匹配文档数量"relation": "eq" // 匹配总数的关系。eq 表示精确数量,gte 表示大于或等于该数量},"max_score": 1.0, // 最高相关性得分,表示匹配度最高的文档的得分"hits": [ // 匹配的文档数组,每个元素代表一个文档的完整信息{"_index": "my_index", // 文档所属的索引名称"_type": "_doc", // 文档的类型(7.x 版本后仅为 _doc)"_id": "1", // 文档的唯一标识符,等同于数据库中的主键"_score": 1.0, // 文档的相关性得分,表示文档与查询的匹配程度"_source": { // 文档的实际内容"name": "Alice", // 文档中的字段"age": 30, // 文档中的字段}},{"_index": "my_index","_type": "_doc","_id": "2","_score": 1.0,"_source": {"name": "Bob","age": 25,"email": "bob@example.com","status": "inactive"}}]}
}

其中hits.hits数组为查询结果列表,而列表中的每个元素的_source属性则是具体数据。

具体操作

我们再次创建一个索引,用于定义数据结构,然后在执行文档相关操作,创建指令如下:

PUT test_index
{"mappings": {"properties": {"name": {"type": "text"},"age": {"type": "integer"}}}
}
1. 新增数据

通过post或put请求,以及/索引名/_doc的uri/id(id也可以不写,由ES自动生成),可以完成新增一条数据,具体如下:

在这里插入图片描述

2. 查询数据

通过get请求,以及_search,搜索全部数据(search可以分词搜索,下面说)

在这里插入图片描述

也可以通过_doc根据id查找

在这里插入图片描述

3. 更改数据

通过_update,可以将指定字段更改(没有指定的不会改变)

在这里插入图片描述

4. 删除数据

通过delete请求可以删除数据

在这里插入图片描述

3. ES的搜索功能

ES中并非所有类型都支持搜索功能,并且支持搜索功能的类型,而可以进行搜索的类型有可以细分为精确搜索(只支持精确搜索),分词搜索和范围搜索

精确搜索
  • keyword:用于精确匹配的字符串搜索,支持过滤、排序和聚合,但不分词。

  • boolean:可以用于布尔值的精确匹配查询。

分词搜索
  • text:用于全文搜索,支持分词、相关性评分、模糊搜索等。
范围搜索
  • date:支持日期范围查询,可以用于过滤、排序、聚合。

  • ip:可以用于 IP 地址的精确匹配和范围查询(支持 IPv4 和 IPv6)。

  • geo_point:用于地理坐标点查询,支持地理距离计算和区域范围查询。

  • range(包括 integer_rangefloat_rangelong_rangedouble_rangedate_range):可以用于范围查询和范围过滤。

剩余的二进制数据**binary,以及object(非嵌套对象)和nested**:支持复杂的嵌套对象都不支持搜索(对象字段支持搜索)。

具体操作

为了方便操作,我们执行以下指令创建一个索引,并插入数据:

#创建索引
PUT /test_search_index
{"mappings": {"properties": {"title": {"type": "text"},"tags": {"type": "keyword"},"publish_date": {"type": "date","format": "yyyy-MM-dd"},"author": {"type": "keyword"},"views": {"type": "integer"},"price": {"type": "float"},"active": {"type": "boolean"},"ip_address": {"type": "ip"},"location": {"type": "geo_point"}}}
}
#一次性插入多条数据
POST /test_search_index/_bulk
{ "index": { "_id": 1 }}
{ "title": "Elasticsearch Guide", "tags": ["search", "guide"], "publish_date": "2023-01-01", "author": "Alice", "views": 100, "price": 9.99, "active": true, "ip_address": "192.168.1.1", "location": "40.730610,-73.935242" }
{ "index": { "_id": 2 }}
{ "title": "Advanced Search", "tags": ["elasticsearch", "search"], "publish_date": "2023-02-01", "author": "Bob", "views": 200, "price": 15.50, "active": false, "ip_address": "192.168.1.2", "location": "34.052235,-118.243683" }
{ "index": { "_id": 3 }}
{ "title": "Elasticsearch and Python", "tags": ["python", "elasticsearch"], "publish_date": "2023-03-15", "author": "Carol", "views": 150, "price": 20.00, "active": true, "ip_address": "192.168.1.3", "location": "51.507351,-0.127758" }
{ "index": { "_id": 4 }}
{ "title": "Text Analysis with Elasticsearch", "tags": ["analysis", "text"], "publish_date": "2023-04-20", "author": "Dave", "views": 300, "price": 25.99, "active": true, "ip_address": "192.168.1.4", "location": "35.689487,139.691711" }
{ "index": { "_id": 5 }}
{ "title": "Geo Search", "tags": ["geo", "search"], "publish_date": "2023-05-10", "author": "Eve", "views": 250, "price": 30.00, "active": false, "ip_address": "192.168.1.5", "location": "48.856613,2.352222" }
{ "index": { "_id": 6 }}
{ "title": "Keyword Search", "tags": ["keyword", "exact"], "publish_date": "2023-06-12", "author": "Frank", "views": 120, "price": 8.99, "active": true, "ip_address": "192.168.1.6", "location": "55.755825,37.617298" }
{ "index": { "_id": 7 }}
{ "title": "Boolean Queries", "tags": ["boolean", "queries"], "publish_date": "2023-07-15", "author": "Grace", "views": 80, "price": 12.49, "active": false, "ip_address": "192.168.1.7", "location": "39.904202,116.407394" }
{ "index": { "_id": 8 }}
{ "title": "Range Queries", "tags": ["range", "queries"], "publish_date": "2023-08-20", "author": "Hank", "views": 180, "price": 17.75, "active": true, "ip_address": "192.168.1.8", "location": "37.774929,-122.419418" }
{ "index": { "_id": 9 }}
{ "title": "Sorting Results", "tags": ["sorting", "results"], "publish_date": "2023-09-25", "author": "Ivy", "views": 220, "price": 22.00, "active": true, "ip_address": "192.168.1.9", "location": "40.712776,-74.005974" }
{ "index": { "_id": 10 }}
{ "title": "Faceted Search", "tags": ["facets", "search"], "publish_date": "2023-10-30", "author": "Jack", "views": 90, "price": 19.95, "active": false, "ip_address": "192.168.1.10", "location": "41.878113,-87.629799" }
1. 精确搜索

在这里插入图片描述

除了必须精确查找的类型外,很多范围查找的也可以使用精确查找,在图中我们也可以发现一个问题,就是tags属性不是数组吗?不过ES可并没有提供一个数组类型啊!

实际上这个数组字段的类型就是keyword,ES中的数组元素必须为同一个类型,也就是是其索引中设置的类型。

搜索中我们使用了query.term来进行搜索,除此之外还有一个query.match搜索的,是用来做分词搜索的,区别在于query.match在查询是会讲查询语句进行分词处理,而query.term则不会。

2. 范围搜索

在这里插入图片描述

3. 分词查询

text是唯一支持分词查询的类型,我们可以在创建改字段时通过改变analyzer属性,选择分析器(默认是standard),然后存入的文本就会根据分词的规则对文本进行分词,生成倒排索引,那么什么是倒排索引呢?假设我门存入一段文字,我爱你中国,那么这段文字可能会被分词为我、爱、你、中国、我爱你,这些词,这这些词又会作为索引指向文本,当我们搜索我爱你时,就会找到这个索引,并返回对应文本,这就是倒排索引。

我们可以通过可以如下请求,对title字段进行搜索,为了方便展示,我们用source属性进行限制,只让他展示title:

在这里插入图片描述

通过图中结果我们可以推测我们的文本被分词为Elasticsearch和guide两个词,然后去ES中搜索倒排索引,并根据结果进行评分(也就是结果的_score属性),评分越高,结果越靠前,最终结果如图所示。

过滤器

过滤器本质是是和query相同的属性,作用和语法都相同,不同的是,filter不会对结果进行评分排序,并且会对结果进行缓存。也就是说filter的查询性能比query更好,这里就不举例了,和query语法一样。

组合查询

组合查询通过如下语法实现:

GET /my_index/_search
{"query": {"bool": {"must": [{ "term": { "status": "active" }},               // 必须为 active{ "range": { "age": { "gte": 25, "lte": 40 }}}   // 年龄在 2540 之间],"should": [{ "match": { "description": "Elasticsearch" }}   // 描述包含 Elasticsearch],"must_not": [{ "match": { "description": "beginner" }}        // 描述不包含 beginner],"minimum_should_match": 2}}
}

其中bool代表了组合查询,而其中must中的查询条件必须全部满足,而should中包含的条件只需要满足一个即可,must_not则是必须不满足,而minimum_should_match表示的是当前组合查询中的should语句知道满足多少条时才返回true,也就是不再只是满足一条就返回true了。

must得到的结果仍然要参与评分,我们可以用filter替换must,实现和过滤器一样的效果。

bool本身也可以作为组合查询的条件之一,也就是死后缩bool也可以作为bool的属性。

4. 分析器

Elasticsearch对于text类型的处理依赖于分析器,分析器能够将text类型文本,按照既定的规则处理为可以搜索的一个个倒排索引。分析器的整个执行过程分为三个阶段,分别是分词前对于字符串的处理,分词,以及分词后对于每个索引的处理,对应的也是分析器的三个部分,分别是字符过滤器,分词器,分词过滤器(或者词条,或者令牌,叫法很多)。

ES中默认了内置了很多的分析器,内容如下:

  • 标准分析器(standard):按语言规则进行分词,将所有词条转为小写,适合一般文本处理。
  • 简单分析器(simple):按非字母字符分词,将词条转换为小写,适合不包含复杂字符的简单文本。
  • 空格分析器(whitespace):按空格分词,不做大小写转换,适合对空格分隔的内容进行简单处理。
  • 停止词分析器(stop):类似标准分析器,分词后去除停用词(如 “and”、“the” 等),适合英文内容的分词处理。
  • 关键词分析器(keyword):将整个文本视为一个词条,不进行分词,适合精确匹配(如邮箱地址或用户ID)。
  • 语言分析器(language,如 english、french、german):针对特定语言进行分词和处理,去掉停用词并进行词干提取,适用于多语言文本。
  • 模式分析器(pattern):基于正则表达式分词,按自定义分隔模式拆分,适合按特定字符或模式分隔的内容。
  • UAX_URL_Email 分析器(uax_url_email):识别 URL 和电子邮件地址作为单独词条,适用于带 URL 或电子邮件的内容。
  • 自定义分析器(custom):用户自定义的分词方式,灵活组合字符过滤、分词和过滤规则,用于满足特殊的文本处理需求。

这些内置的分析器,都是可以直接配置给text类型属性使用的。

4.1 字符过滤器

字符过滤器用于在分词前对文本进行处理,比如说html_strip分词器可以在分词前,先将文本进行去除html标签处理。内置分析器中没有使用过字符过滤器,不过我们可以使用字符过滤器在我们的自定义分析器中,ES提供的字符过滤器如下:

  • html_strip:去除 HTML 标签。
  • mapping:将字符或字符串替换为其他内容,支持自定义映射。
  • pattern_replace:使用正则表达式对字符或字符串进行替换。

4.2 分词器

无需多言,没有分词器怎么分词,ES提供分词器如下:

  • standard:默认的分词器,基于语言规则进行分词。
  • whitespace:按空格分词,不做进一步处理。
  • keyword:将整个输入文本视为一个词条,不进行分词,适用于精确匹配。
  • pattern:基于正则表达式分词,可以自定义分隔模式。
  • uax_url_email:适用于带有 URL 和电子邮件地址的文本的分词器。
  • ngram:基于字符的 n-gram 分词器,适合模糊匹配。
  • edge_ngram:基于字符的边界 n-gram 分词器,生成从开头的 n-gram,适合自动完成。
  • classic:类似 standard 分词器的旧版本,适用于英文文本。
  • letter:按字母字符分词,遇到非字母字符断开。
  • lowercase:转换为小写的 keyword 分词器,整个文本视为一个词条并小写化。
  • path_hierarchy:基于路径层级的分词器,适用于文件路径、URL 分级等。
  • char_group:按字符组分词,可以指定多个字符作为分隔符。

4.3 分词过滤器

分词过滤器是对分词后的索引再次进行处理,比如说当我们使用内置的standard分析器时,rm可以搜索到分词后的Rm索引,原因就是standard分析器使用了lowercase分词过滤器,ES提供的分词过滤器如下:

  • lowercase:将词条转换为小写。
  • uppercase:将词条转换为大写。
  • stop:去除停用词(例如 andthe),支持多种语言的停用词。
  • stemmer:词干提取器,将词条转换为词干(如 running 转为 run),支持多种语言。
  • asciifolding:将带重音符号的字符转换为 ASCII 字符(如 é 转为 e)。
  • synonym:替换同义词(如 quickfast 可以替换为彼此)。
  • shingle:生成包含多个词的组合(例如 New York 生成 New, York, New York),用于短语匹配。
  • ngram:基于词条的 n-gram,生成较小的词条,适合模糊匹配。
  • edge_ngram:基于词条的边界 n-gram,从词条开头生成较小的词条,适合自动完成。
  • unique:去除重复的词条。
  • reverse:将词条的字符顺序反转。
  • length:过滤指定长度范围外的词条。
  • truncate:将词条截断为指定长度。
  • porter_stem:使用 Porter 词干算法,提取英文词条的词干。
  • kstem:另一种英文词干算法,提取英文词条的词干。
  • snowball:使用 Snowball 词干算法,支持多种语言的词干提取。
  • fingerprint:为多词条生成指纹标识,去重并排序,适用于重复检测。
  • limit:限制词条数目,截断超出指定数量的词条。
  • pattern_capture:使用正则表达式捕获匹配模式的子部分。
  • pattern_replace:使用正则表达式替换词条内容。

ES并没有内置中文分词器,对于中文的分词我们可以使用IK分词器来实现。

我们可以进入IK的github地址,在下面的readme中提供了安装命令

bin/elasticsearch-plugin install https://get.infini.cloud/elasticsearch/analysis-ik/8.4.1

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.4 自定义分析器

了解了分析器的三个部分后,我们就可以自由组合这三个部分,实现自己的自定义分析器,实例如下:

PUT my_index
{"settings": {"analysis": {"char_filter": {"mapping_filter": {"type": "mapping","mappings": ["$=>USD", "&=>and", "%=> percent"]}},"tokenizer": {"whitespace_tokenizer": {"type": "whitespace"}},"filter": {"lowercase_filter": {"type": "lowercase"},"english_stop_filter": {"type": "stop","stopwords": "_english_"}},"analyzer": {"my_custom_analyzer": {"type": "custom","char_filter": ["html_strip_filter""html_strip"],"tokenizer": "whitespace_tokenizer","filter": ["lowercase_filter", "english_stop_filter"]}}}}
}

实例中,我们在setting.analysis属性中,定义了字符过滤器mapping_filter,分词器whitespace_tokenizer,分词过滤器lowercase_filter和english_stop_filter。并将三者在analyzer中共同组合成了一个新的自定义分析器my_custom_analyzer。

像html_strip这种功能固定,无需配置的,可以直接放入自定义分析器中。

5. 词库

分析器功能虽然强大,不过其也是根据人类的语言习惯来进行分词,那么对于一些网络新型的热词,ES该如何分辨呢。这就涉及到更改词库的操作。

词库种类很多,不用的解析器能够使用的词库种类也不同(分词规则不同,词库当然也不同)。

比如说ES本身支持六种词库,包括:

  • 停用词库:用于过滤无意义的常见词。
  • 同义词库:用于归类同义词,增强召回率。
  • 词干提取词库:用于词态还原,统一不同词态。
  • 关键词映射词库:用于标准化关键术语。
  • 拼写纠正词库:用于修正拼写错误,提高搜索容错。
  • 停用词变体词库:适合特定领域的停用词。

而这六种词库,IK分析器能够识别的只有停用词库,同一词库,以及停用词变体词库。与其说IK只识别,倒不如说只有这三种词库对中文分词有帮助,所以不同的分析器,需要的词库也不同,完全根据分析器本身的性质来(ES内置的分析器也对这些词库的使用不完全兼容)。

具体操作

以停用词库为例,我们可以在自定义stop类型的分词过滤器时,给stopwords_path属性设置路径,示例如下:

PUT my_index
{"settings": {"analysis": {"filter": {"custom_stopwords": {"type": "stop","stopwords_path": "analysis/stopwords.txt"  // 指定停用词库文件路径}},"analyzer": {"my_analyzer": {"type": "custom","tokenizer": "standard","filter": ["lowercase", "custom_stopwords"]}}}}

这样ES就会去寻找conf/analysis/stopwords.txt文件中,读取其中的停用词信息(一行为一词)。

而对于IK分析器,其可以在配置文件中配置远程词库链接(就是一个txt文件的链接)实现远程词库,以及基于mysql的远程词库,这里就不多说了。

6. 聚合查询

聚合查询就是将大量数据结合在一起查询,获取一些公共的数据。ES中聚合查询分为三种,分别为桶聚合(Bucket Aggregation)度量聚合(Metric Aggregation)管道聚合(Pipeline Aggregation)

为了方便演示,我创建如下索引及数据

PUT products
{"mappings": {"properties": {"description": {"type": "text",},"category": {"type": "keyword"},"price": {"type": "float"},"rating": {"type": "integer"},"timestamp": {"type": "date"}}}
}
POST products/_bulk
{ "index": { "_id": 1 } }
{ "description": "高性能的Elasticsearch搜索引擎", "category": "电子产品", "price": 299.99, "rating": 4, "timestamp": "2023-01-10T12:00:00" }
{ "index": { "_id": 2 } }
{ "description": "Elasticsearch用于大数据分析", "category": "软件", "price": 199.99, "rating": 5, "timestamp": "2023-01-15T12:00:00" }
{ "index": { "_id": 3 } }
{ "description": "时尚服装,舒适体验", "category": "服装", "price": 49.99, "rating": 3, "timestamp": "2023-02-10T12:00:00" }
{ "index": { "_id": 4 } }
{ "description": "优质材料的服装", "category": "服装", "price": 79.99, "rating": 4, "timestamp": "2023-02-12T12:00:00" }
{ "index": { "_id": 5 } }
{ "description": "家用实木家具", "category": "家具", "price": 499.99, "rating": 5, "timestamp": "2023-03-01T12:00:00" }
{ "index": { "_id": 6 } }
{ "description": "现代风格的家具", "category": "家具", "price": 299.99, "rating": 3, "timestamp": "2023-03-05T12:00:00" }
{ "index": { "_id": 7 } }
{ "description": "智能家电,方便生活", "category": "家电", "price": 1200.00, "rating": 5, "timestamp": "2023-04-01T12:00:00" }
{ "index": { "_id": 8 } }
{ "description": "高效节能的家电", "category": "家电", "price": 850.00, "rating": 4, "timestamp": "2023-04-03T12:00:00" }
{ "index": { "_id": 9 } }
{ "description": "新鲜食品,健康选择", "category": "食品", "price": 15.00, "rating": 4, "timestamp": "2023-05-10T12:00:00" }
{ "index": { "_id": 10 } }
{ "description": "有机食品,绿色生活", "category": "食品", "price": 10.00, "rating": 3, "timestamp": "2023-05-12T12:00:00" }

6.1 桶聚合(Bucket Aggregation)

桶聚合就是将数据按照某个属性的的不同,进行分桶(其实就是简单的分类),实例如下:

在这里插入图片描述

查询方法就是通过/索引名/_search,然后请求体中的size:0是为了不展示查询的数据,只展示分桶数据。而aggs就是聚合查询的属性,在其中我们可以创建一个聚合类型的名称,这里我起的名称是bucket,其中terms代表的就是桶聚合,而field则是选择桶聚合的属性。

如图所示,结果是通过category属性将数据粉了六类,并标记了每个种类的数量。

对于text属性的桶聚合比较特殊。在创建索引时,映射中与属性类型同级的配置,还有一个fileddata,这个属性是用于对属性生成正排索引的,处text外,其他索引都支持精确查询,索引需要正排索引,所以这个值都是true。而text不支持精确搜索,其搜索功能依赖倒排索引,所以fileddata是false。但是分桶依赖的也是正排索引,所以text默认情况下并不支持分桶聚合,示例如下:

在这里插入图片描述

但是我们如果将fieldata设置为true呢,我们通过如下请求,将其设置为true:

POST products/_mapping
{"properties":{"description":{"type":"text",#类型必须在写一次,并且和原来一样"fielddata": true}}
}

在这里插入图片描述

可以看到,虽然分词成功了,但是结果很奇怪。实际上对text类型的分桶会根据分词后的结果进行分桶,而图中结果是因为ES内置的分词器不会对中文进行分词,所以结果就是一个字一个类。

而且数量也不够,这是因为与field属性平级的还有一个属性size,这个属性可以控制结果的数量,默认最多分为十个桶。

实际生产中如何设计text类型进行分桶的操作,通常是给其设置一个keyword类型的属性,然后通过对这个属性的分桶,来对text分桶,假设我们的description有一个tag属性,那么我们只需要在field属性中赋值description.tag即可。

6.2 度量聚合

度量聚合就是对数据进行计算,比如最大值,最小值,平均值等,具体如下

GET products/_search
{"size": 0,"aggs": {"average_price": {"avg": {"field": "price"}},"total_price": {"sum": {"field": "price"}},"max_price": {"max": {"field": "price"}},"min_price": {"min": {"field": "price"}},"price_count": {"value_count": {"field": "price"}}}
}

在这里插入图片描述

通过度量聚合可以对数据进行统计计算

6.3 管道聚合

管道聚合就是将一种聚合的结果,交给另一个聚合计算。

在这里插入图片描述

如图所示,可以在聚合的统计在写一个aggs,接受上一个聚合结果,也可以i通过buckets_path来指定路径。

6.4 将查询结果进行聚合查询

我们可以将query查询的结果,在使用aggs进行聚合查询,示例如下:

在这里插入图片描述

如图,我们将价格大于一百的产品拿出来,在进行分桶。

6.5 脚本查询

Elasticsearch 支持的脚本语言包括 Painless(默认和推荐),并支持 expressionmustache 等语言。下面我们重点介绍如何使用 Painless。我们可以在其script.source属性上编写查询脚本,示例如下:

在这里插入图片描述

图中第一个命令是以脚本作为条件,第二个是自己创建一个属性,用脚本计算值,并且支持传参。

7. 搜索推荐

在使用搜索引擎的搜索框时,当我们输入一部分文字,底部弹窗机会弹出我们可能想要搜索的东西,这个功能就是搜索推荐,搜索推荐的功能本质上也是通过输入的一部分,搜索全部部分,但是和搜索text类型文本不同的是,搜索推荐搜索的是分词后的倒排索引(也可以说是词库里的热词)返回给用户,方便用户进行搜索。

搜索推荐本质上也是搜索,是通过ES提供的suggest关键字实现的,其中包含一下四类实现

7.1 completion Suggester

功能completion suggester 是一种用于实现自动完成(autocomplete)的建议器。它基于轻量级的索引结构(FST,有限状态转换器),可以实现快速的前缀匹配,非常适合用于实时的搜索推荐。

常用参数

  • field:指定用于自动完成的字段(通常是 completion 类型的字段)。
  • prefix:用户输入的前缀,建议器将提供与该前缀匹配的推荐项。
  • size:控制返回的建议项数量。
  • fuzzy:用于启用模糊匹配(例如拼写错误时也能匹配),可以设置 fuzziness 参数来调整模糊匹配的程度。

示例

POST products/_search
{"suggest": {"product-suggest": {"prefix": "iph","completion": {"field": "suggest","size": 5,"fuzzy": {"fuzziness": 2}}}}
}

7.2 term Suggester

功能term suggester 用于拼写纠错,可以在用户输入有错字时推荐正确的词。它基于倒排索引,适合单个词的拼写纠错。

常用参数

  • field:指定拼写建议的字段。

  • text:用户输入的文本,建议器将对该文本进行拼写检查。

  • suggest_mode

    :指定建议模式,可以是:

    • missing:仅当词项缺失时才进行建议。
    • popular:仅对频率最高的词进行建议。
    • always:总是提供建议。
  • max_edits:指定允许的编辑距离(即拼写错误的字符数),默认为 2。

  • prefix_length:指定匹配前缀的最小长度,减少计算量。

  • size:控制返回的建议项数量。

示例

POST products/_search
{"suggest": {"text": "iphon","spellcheck-suggest": {"term": {"field": "name","suggest_mode": "always","max_edits": 1,"size": 3}}}
}

7.3 phrase Suggester

功能phrase suggester 用于长查询的拼写纠错,特别适合基于上下文的拼写建议。例如,当用户输入多个单词时,phrase suggester 可以利用上下文信息来提供更智能的拼写建议。

常用参数

  • field:指定用于建议的字段,一般设置为 text 字段。

  • text:用户输入的文本,建议器将检查其中的拼写和上下文。

  • size:控制返回的建议项数量。

  • gram_size:指定 n-gram 的大小,通常设置为 2 或 3,用于基于上下文生成的建议。

  • direct_generator

    :用于控制建议生成的方式,可以指定多个生成器,参数包括:

    • field:指定字段。
    • suggest_mode:建议模式,类似于 term suggester。
    • min_word_length:建议生成器适用的最小单词长度。
    • prefix_length:最小前缀长度。
    • size:每个生成器返回的建议项数量。
  • highlight:用于高亮拼写建议的部分,通常包含 pre_tagpost_tag 参数,用于包裹拼写建议的高亮标记。

示例

POST products/_search
{"suggest": {"text": "iphon apple","phrase-suggest": {"phrase": {"field": "name.trigram","size": 1,"gram_size": 3,"direct_generator": [{"field": "name","suggest_mode": "always","min_word_length": 3}],"highlight": {"pre_tag": "<em>","post_tag": "</em>"}}}}
}

7.4 context Suggester

功能context suggester 是 completion suggester 的扩展,用于在自动完成推荐中增加上下文信息的过滤。例如,可以根据地理位置、类别、时间等上下文条件来过滤建议项。

常用参数

  • field:指定 completion 类型的字段。

  • prefix:用户输入的前缀。

  • contexts

    :用于指定上下文条件,可以是地理位置、类别等。

    • location:可以指定一个地理位置范围,例如 { "lat": 40.71, "lon": -74.01 }
    • category:可以指定一个分类标签,例如 "electronics"

示例

POST products/_search
{"suggest": {"product-suggest": {"prefix": "iph","completion": {"field": "suggest","size": 5,"contexts": {"category": ["electronics"]}}}}
}
解释

在这个示例中,context 被设置为 category,只有符合 "electronics" 分类的建议项会被返回。

我们没办法讲所有命令全部记在脑子里,对于ES的学习,我们的目的也只是知道ES能干什么,大致有什么东西,对于实际的需求,还是需要在实际解决时搜索对应命令。除了文中给的指令外,ES的指令还有非常多,这里也不多介绍了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/60740.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无插件H5播放器EasyPlayer.js网页web无插件播放器vue和react详细介绍

EasyPlayer.js H5播放器&#xff0c;是一款能够同时支持HTTP、HTTP-FLV、HLS&#xff08;m3u8&#xff09;、WS、WEBRTC、FMP4视频直播与视频点播等多种协议&#xff0c;支持H.264、H.265、AAC、G711A、Mp3等多种音视频编码格式&#xff0c;支持MSE、WASM、WebCodec等多种解码方…

Ubuntu 的 ROS 操作系统安装与测试

引言 机器人操作系统&#xff08;ROS, Robot Operating System&#xff09;是一个用于开发机器人应用的开源框架&#xff0c;它提供了一系列功能丰富的库和工具&#xff0c;能够帮助开发者构建和控制机器人。 当前&#xff0c;ROS1的最新版本为Noetic Ninjemys&#xff0c;专为…

入门网络安全工程师要学习哪些内容(详细教程)

&#x1f91f; 基于入门网络安全/黑客打造的&#xff1a;&#x1f449;黑客&网络安全入门&进阶学习资源包 大家都知道网络安全行业很火&#xff0c;这个行业因为国家政策趋势正在大力发展&#xff0c;大有可为!但很多人对网络安全工程师还是不了解&#xff0c;不知道网…

IP数据云 识别和分析tor、proxy等各类型代理

在网络上使用代理&#xff08;tor、proxy、relay等&#xff09;进行访问的目的是为了规避网络的限制、隐藏真实身份或进行其他的不正当行为。 对代理进行识别和分析可以防止恶意攻击、监控和防御僵尸网络和提高防火墙效率等&#xff0c;同时也可以对用户行为进行分析&#xff…

【C#设计模式(10)——装饰器模式(Decorator Pattern)】

前言 装饰器模式可以在运行时为对象添加额外的功&#xff0c;而无需修改原始对象的代码。这种方式比继承更加灵活。 代码 //蛋糕类&#xff08;抽象类&#xff09; public abstract class Cake {public abstract void Create(); } //奶油蛋糕类 public class CreamCake : Cak…

【论文速读】| 注意力是实现基于大语言模型的代码漏洞定位的关键

基本信息 原文标题&#xff1a;Attention Is All You Need for LLM-based Code Vulnerability Localization 原文作者&#xff1a;Yue Li, Xiao Li, Hao Wu, Yue Zhang, Xiuzhen Cheng, Sheng Zhong, Fengyuan Xu 作者单位&#xff1a;National Key Laboratory for Novel So…

python包管理工具pip和conda的使用对比

python包管理工具pip和conda的使用对比 总述1. pip使用2. conda注意虚拟环境之间的嵌套&#xff0c;这个会导致安装包后看不到包&#xff0c;实际是安装到了base环境里 未完待续 总述 pip相对于conda,对应包的依赖关系管理不强&#xff0c;坏处是容易造成包冲突&#xff0c;好…

Diff 算法的误判

起源&#xff1a; for循环的:key的值使用index绑定&#xff0c;当循环列表条目变化更新&#xff0c;导致虚拟 DOM Diff 算法认为原有项被替换&#xff0c;而不是更新。 // vue2写法 错误例子 <template><div><button click"addItem">添加项目<…

Python与其他语言比较·练习题 --- 《跟着小王学Python》

Python与其他语言比较练习题 — 《跟着小王学Python》 《跟着小王学Python》 是一套精心设计的Python学习教程&#xff0c;适合各个层次的学习者。本教程从基础语法入手&#xff0c;逐步深入到高级应用&#xff0c;以实例驱动的方式&#xff0c;帮助学习者逐步掌握Python的核心…

如何修改npm包

前言 开发中遇到一个问题&#xff0c;配置 Element Plus 自定义主题时&#xff0c;添加了 ElementPlusResolver({ importStyle: "sass" }) 后&#xff0c;控制台出现报错&#xff0c;这是因为 Dart Sass 2.0 不再支持使用 !global 来声明新变量&#xff0c;虽然当前…

[CKS] K8S RuntimeClass SetUp

最近准备花一周的时间准备CKS考试&#xff0c;在准备考试中发现有一个题目关于RuntimeClass创建和挂载的题目。 ​ 专栏其他文章: [CKS] Create/Read/Mount a Secret in K8S-CSDN博客[CKS] Audit Log Policy-CSDN博客 -[CKS] 利用falco进行容器日志捕捉和安全监控-CSDN博客[CKS…

第三百二十五节 Java线程教程 - Java Fork/Join框架

Java线程教程 - Java Fork/Join框架 fork/join框架通过利用机器上的多个处理器或多个内核来解决问题。 该框架有助于解决涉及并行性的问题。 fork/join框架创建一个线程池来执行子任务。 当线程在子任务上等待完成时&#xff0c;框架使用该线程来执行其他线程的其他未决子任…

Vue3集成搜索引擎智能提示API

需求&#xff1a; 如何在项目中实现像百度搜索框一样的智能提示效果&#xff0c;如下图所示&#xff1a; 相关知识&#xff1a; 下面是各厂商提供的免费API 厂商请求百度http://suggestion.baidu.com/su?wd中国&cbwindow.baidu.sug必应http://api.bing.com/qsonhs.as…

一文了解Android的核心系统服务

在 Android 系统中&#xff0c;核心系统服务&#xff08;Core System Services&#xff09;是应用和系统功能正常运行的基石。它们负责提供系统级的资源和操作支持&#xff0c;包含了从启动设备、管理进程到提供应用基础组件的方方面面。以下是 Android 中一些重要的核心系统服…

鸿蒙实战:页面跳转

文章目录 1. 实战概述2. 实现步骤2.1 创建项目2.2 准备图片素材2.3 编写首页代码2.4 创建第二个页面 3. 测试效果4. 实战总结 1. 实战概述 实战概述&#xff1a;本实战通过ArkUI框架&#xff0c;在鸿蒙系统上开发了一个简单的两页面应用。首页显示问候语和“下一页”按钮&…

2023_Spark_实验十五:SparkSQL进阶操作

实验目标 通过实践掌握Spark SQL中复杂查询&#xff08;包括子查询、窗口函数、联接等&#xff09;的实现方式。了解如何通过合理的数据分区和缓存策略进行性能优化。实现一个基于Spark SQL的ETL数据处理流程&#xff0c;应用相关优化技巧。 实验背景 在本实验中&#xff0c…

大模型研究报告 | 2024年中国金融大模型产业发展洞察报告|附34页PDF文件下载

随着生成算法、预训练模型、多模态数据分析等AI技术的聚集融合&#xff0c;AIGC技术的实践效用迎来了行业级大爆发。通用大模型技术的成熟推动了新一轮行业生产力变革&#xff0c;在投入提升与政策扶植的双重作用下&#xff0c;以大模型技术为底座、结合专业化金融能力的金融大…

MySQL联合索引(abc)命中测试

1.建表 mysql创建一张表&#xff0c;表名&#xff1a;‘test_models’ id列为 主键&#xff0c;int类型 &#xff0c;自增a,b,c,d,e 全部是int&#xff08;11&#xff09;为&#xff08;a,b,c&#xff09;添加一个联合索引 index_abc 执行语句&#xff1a;创建表 CREATE TA…

Gin 框架入门(GO)-1

1 介绍 Gin 是一个 Go (Golang) 编写的轻量级 http web 框架&#xff0c;运行速度非常快&#xff0c;Gin 最擅长的就是 Api 接口的高并发。 2 Gin 环境搭建 1.下载并安装 gin go get -u github.com/gin-gonic/gin 2.将 gin 引入到代码中&#xff1a; import "github.co…

VUE3+Three.js搭建教程

一、创建VUE项目工程 1、方法一 使用下面命令行快速创建vue项目&#xff0c;Please pick a preset这里我们选择使用VUE3 vue create projectName 创建时可能会遇到的报错 错误原因&#xff1a;当前使用的node版本未全局安装vue-cli脚手架&#xff0c;使用下面命令安装后再使…