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的指令还有非常多,这里也不多介绍了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

常用命令之LinuxOracleHivePython

1. 用户改密 passwd app_adm chage -l app_adm passwd -x 90 app_adm -> 执行操作后&#xff0c;app_adm用户的密码时间改为90天有效期--查看该euser用户过期信息使用chage命令 --chage的参数包括 ---m 密码可更改的最小天数。为零时代表任何时候都可以更改密码。 ---M 密码…

华为HCIP——MSTP/RSTP与STP的兼容性

一、MSTP/RSTP与STP的兼容性的原理&#xff1a; 1.BPDU版本号识别&#xff1a;运行MSTP/RSTP协议的交换机会根据收到的BPDU&#xff08;Bridge Protocol Data Unit&#xff0c;桥协议数据单元&#xff09;版本号信息自动判断与之相连的交换机的运行模式。如果收到的是STP BPDU…

Visual Studio 2022 安装

下载链接 https://visualstudio.microsoft.com/zh-hans/thank-you-downloading-visual-studio/?skuCommunity&channelRelease&versionVS2022&sourceVSLandingPage&cid2030&passivefalse 安装 以c为例&#xff0c;列出需要勾选的项目&#xff0c;有3个&a…

文件 fd

&#x1f3f7;️ 预备工作 ❓ 当我们在系统中创建一个空文件时&#xff0c;这个文件要不要占据磁盘的空间&#xff08;注意是空文件哟&#xff09; 答案&#xff1a;当然是要占据磁盘的空间的&#xff0c;文件不仅只包括内容&#xff0c;还有它的属性呀&#xff0c;就是创建时…

树的直径计算:算法详解与实现

树的直径计算:算法详解与实现 1. 引言2. 算法概述3. 伪代码实现4. C语言实现5. 算法分析6. 结论在图论中,树的直径是一个关键概念,它表示树中任意两点间最长路径的长度。对于给定的树T=(V,E),其中V是顶点集,E是边集,树的直径定义为所有顶点对(u,v)之间最短路径的最大值。…

RHCSA学习超详细知识点2命令篇

输入命令行的语法 终端中执行命令需要遵照一定的语法&#xff0c;输入命令的格式如下&#xff1a; 命令 参数命令 -选项 参数 输入命令时可以包含多个选项&#xff0c;假如一个命令有-a,-b,-c,-d四个选项&#xff0c;可以写作 命令 -a -b -c -d 参数 这里的多个选项可以“提…

3步实现贪吃蛇

方法很简单&#xff0c;打开页面&#xff0c;复制&#xff0c;粘贴 一.整体思维架构 我们根据游戏的开始&#xff0c;运行&#xff0c;结束&#xff0c;将整个游戏划分成三个部分。在每个部分下面又划分出多个功能&#xff0c;接下来我们就根据模块一一实现功能。 二.Gamesta…

风电电力系统低碳调度论文阅读第一期

在碳交易市场中&#xff0c;历史法和基准线法是用于分配碳排放配额的两种主要方法。以下是两种方法的公式及其解释&#xff1a; 区别总结 历史法&#xff1a;基于历史排放量&#xff0c;分配具有较强的公平性但可能缺乏激励减排。基准线法&#xff1a;基于行业基准和生产量&am…

Mybatis-Plus 多租户插件属性自动赋值

文章目录 1、Mybatis-Plus 多租户插件1.1、属性介绍1.2、使用多租户插件mavenymlThreadLocalUtil实现 定义,注入租户处理器插件测试domianservice & ServiceImplmapper 测试mapper.xml 方式 1.3、不使用多租户插件 2、实体对象的属性自动赋值使用1. 定义实体类2. 实现 Meta…

CSS基础知识05(弹性盒子、布局详解,动画,3D转换,calc)

目录 0、弹性盒子、布局 0.1.弹性盒子的基本概念 0.2.弹性盒子的主轴和交叉轴 0.3.弹性盒子的属性 flex-direction row row-reverse column column-reverse flex-wrap nowrap wrap wrap-reverse flex-dirction和flex-wrap的组合简写模式 justify-content flex-s…

使用Web Animations API实现复杂的网页动画效果

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用Web Animations API实现复杂的网页动画效果 使用Web Animations API实现复杂的网页动画效果 使用Web Animations API实现复杂…

Matlab多输入单输出之倾斜手写数字识别

本本主要介绍使用matlab构建多输入单输出的网络架构&#xff0c;来实现倾斜的手写数字识别&#xff0c;使用concatenationLayer来拼接特征&#xff0c;实现网络输入多个特征。 1.加载训练数据 加载数据&#xff1a;手写数字的图像、真实数字标签和数字顺时针旋转的角度。 lo…

pytest结合allure做接口自动化

这是一个采用pytest框架&#xff0c;结合allure完成接口自动化测试的项目&#xff0c;最后采用allure生成直观美观的测试报告&#xff0c;由于添加了allure的特性&#xff0c;使得测试报告覆盖的内容更全面和阅读起来更方便。 1. 使用pytest构建测试框架&#xff0c;首先配置好…

【无人机设计与控制】基于MATLAB的四旋翼无人机PID双闭环控制研究

摘要 本文基于MATLAB/Simulink环境&#xff0c;对四旋翼无人机进行了PID双闭环控制设计与仿真研究。通过分析四旋翼无人机的动力学模型与运动学模型&#xff0c;建立了姿态和位置双闭环控制系统&#xff0c;以实现无人机的稳定飞行与精确轨迹跟踪。仿真实验验证了该控制策略的…

强大的正则表达式——Easy

进入题目界面输入难度1后&#xff0c;让我们输入正则表达式&#xff08;regex&#xff09;&#xff1a; 目前不清楚题目要求&#xff0c;先去下载附件查看情况&#xff1a; import re import random# pip install libscrc import libscrcallowed_chars "0123456789()|*&q…

pytest | 框架的简单使用

这里写目录标题 单个文件测试方法执行测试套件的子集测试名称的子字符串根据应用的标记进行选择 其他常见的测试命令 pytest框架的使用示例 pytest将运行当前目录及其子目录中test_*.py或 *_test.py 形式的所有 文件 文件内的函数名称可以test* 或者test_* 开头 单个文件测试…

【安卓恶意软件检测-论文】DroidEvoler:自我进化的 Android 恶意软件检测系统

DroidEvolver&#xff1a;自我进化的 Android 恶意软件检测系统 摘要 鉴于Android框架的频繁变化和Android恶意软件的不断演变&#xff0c;随着时间的推移以有效且可扩展的方式检测恶意软件具有挑战性。为了应对这一挑战&#xff0c;我们提出了DroidEvolver&#xff0c;这是一…

Vulnhub靶场 Billu_b0x 练习

目录 0x00 准备0x01 主机信息收集0x02 站点信息收集0x03 漏洞查找与利用1. 文件包含2. SQL注入3. 文件上传4. 反弹shell5. 提权&#xff08;思路1&#xff1a;ssh&#xff09;6. 提权&#xff08;思路2&#xff1a;内核&#xff09;7. 补充 0x04 总结 0x00 准备 下载链接&#…

LabVIEW弧焊参数测控系统

在现代制造业中&#xff0c;焊接技术作为关键的生产工艺之一&#xff0c;其质量直接影响到最终产品的性能与稳定性。焊接过程中&#xff0c;电流、电压等焊接参数的精确控制是保证焊接质量的核心。基于LabVIEW开发的弧焊参数测控系统&#xff0c;通过实时监控和控制焊接过程中关…

CentOS网络配置

上一篇文章&#xff1a;VMware Workstation安装Centos系统 在CentOS系统中进行网络配置是确保系统能够顺畅接入网络的重要步骤。本文将详细介绍如何配置静态IP地址、网关、DNS等关键网络参数&#xff0c;以帮助需要的人快速掌握CentOS网络配置的基本方法和技巧。通过遵循本文的…