Elasticsearch基本概念及使用

news2025/1/20 17:48:51

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.coloradmin.cn/o/2242966.html

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

相关文章

黑马智慧商城项目学习笔记

目录 智慧商城项目创建项目调整初始化目录vant组件库vant按需导入和全部导入 项目中的vw适配路由设计配置登录页静态布局图形验证码功能request模块-axios封装api模块-封装图片验证码接口 Toast轻提示&#xff08;vant组件&#xff09;短信验证倒计时功能登录功能响应拦截器统一…

攻防世界Web-bug

打开链接 先注册一个账号 创建成功&#xff0c;会给一个UID5 抓包的user值就是UID:用户名的md5加密的编码 点击Manage时要求admin用户 利用改包把user改成admin 1:admin的md5值为4b9987ccafacb8d8fc08d22bbca797ba 还要把url上的UID改为1 存在逻辑漏洞&#xff0c;成功越权 …

apk反编译修改教程系列-----apk应用反编译中AndroidManifest.xml详细代码释义解析 包含各种权限 代码含义【二】

💝💝💝💝在上期博文中解析了一个常规apk中 AndroidManifest.xml的权限以及代码。应粉丝需求。这次解析一个权限较高的apk。这款apk是一个家长管控的应用。需求的各种权限较高。而且通过管控端可以设置控制端的app隐藏与否。 通过博文了解💝💝💝💝 1💝💝…

湘潭大学软件工程算法设计与分析考试复习笔记(一)

文章目录 前言随机类&#xff08;第七章&#xff09;随机概述数值随机化舍伍德拉斯维加斯蒙特卡罗 模拟退火遗传人工神经网络 回溯&#xff08;第五章&#xff09;动态规划&#xff08;第四章&#xff09;后记 前言 考试还剩十一天&#xff0c;现在准备开始复习这门课了。好像全…

如何使用正则表达式验证域名

下面是一篇关于如何使用正则表达式验证域名的教程。 如何使用正则表达式验证域名 简介 域名是互联网上网站的地址&#xff0c;每个域名由多个标签&#xff08;label&#xff09;组成&#xff0c;标签之间用点 . 分隔。域名规则有很多细节&#xff0c;但基本要求是&#xff1a…

【Cesium】自定义材质,添加带有方向的滚动路线

【Cesium】自定义材质&#xff0c;添加带有方向的滚动路线 &#x1f356; 前言&#x1f3b6;一、实现过程✨二、代码展示&#x1f3c0;三、运行结果&#x1f3c6;四、知识点提示 &#x1f356; 前言 【Cesium】自定义材质&#xff0c;添加带有方向的滚动路线 &#x1f3b6;一、…

DDoS高防服务器:保障业务安全和稳定的抗攻击利器

摘要 随着网络攻击愈发频繁&#xff0c;尤其是DDoS&#xff08;分布式拒绝服务&#xff09;攻击的威胁不断增长&#xff0c;DDoS高防服务器成为保护企业网络安全的重要工具。本文将详细介绍DDoS高防服务器的原理、优势、应用场景及选择要点&#xff0c;帮助企业有效应对攻击&am…

vim配置 --> 在创建的普通用户下

在目录/etc/ 下面&#xff0c;有个名为vimrc 的文件&#xff0c;这是系统中公共的vim配置文件对所有用户都有效 我们现在创建一个普通用户 dm 创建好以后&#xff0c;我们退出重新链接 再切换到普通用户下 再输入密码&#xff08;是不显示的&#xff0c;输入完后&#xff0c;…

Python 正则表达式使用指南

Python 正则表达式使用指南 正则表达式&#xff08;Regular Expression, 简称 regex&#xff09;是处理字符串和文本的强大工具。它使用特定的语法定义一组规则&#xff0c;通过这些规则可以对文本进行匹配、查找、替换等操作。Python 提供了 re 模块&#xff0c;使得正则表达…

Golang | Leetcode Golang题解之第565题数组嵌套

题目&#xff1a; 题解&#xff1a; func arrayNesting(nums []int) (ans int) {n : len(nums)for i : range nums {cnt : 0for nums[i] < n {i, nums[i] nums[i], ncnt}if cnt > ans {ans cnt}}return }

微服务day10-Redis面试篇

Redis主从 搭建主从集群 建立集群时主节点会生成同一的replicationID,交给各个从节点。 集群中的缓冲区是一个环型数组&#xff0c;即若从节点宕机时间过长&#xff0c;可能导致命令被覆盖。 主从集群优化 哨兵原理 哨兵是一个集群来确保哨兵不出现问题。 服务状态监控 选举…

排序算法 -快速排序

文章目录 1. 快速排序&#xff08;Quick Sort&#xff09;1.1、 简介1.2、 快速排序的步骤 2. Hoare 版本2.1、 基本思路1. 分区&#xff08;Partition&#xff09;2. 基准选择&#xff08;Pivot Selection&#xff09;3. 递归排序&#xff08;Recursive Sorting&#xff09; 2…

01、Spring MVC入门程序

概述&#xff1a; MVC(M&#xff1a;模型、V&#xff1a;视图、 C&#xff1a;控制器) 三层架构&#xff1a; 表现层&#xff08;Web层&#xff09;业务层&#xff08;Service层&#xff09;负责业务逻辑处理持久层&#xff08;Dao层&#xff09;负责和数据库交互 Spring MVC 作…

7.揭秘C语言输入输出内幕:printf与scanf的深度剖析

揭秘C语言输入输出内幕&#xff1a;printf与scanf的深度剖析 C语言往期系列文章目录 往期回顾&#xff1a; VS 2022 社区版C语言的安装教程&#xff0c;不要再卡在下载0B/s啦C语言入门&#xff1a;解锁基础概念&#xff0c;动手实现首个C程序C语言概念之旅&#xff1a;解锁关…

Android Osmdroid + 天地图 (一)

Osmdroid 天地图 前言正文一、配置build.gradle二、配置AndroidManifest.xml三、获取天地图的API Key① 获取开发版SHA1② 获取发布版SHA1 四、请求权限五、显示地图六、源码 前言 Osmdroid是一款完全开源的地图基本操作SDK&#xff0c;我们可以通过这个SDK去加一些地图API&am…

️️一篇快速上手 AJAX 异步前后端交互

AJAX 1. AJAX1.1 AJAX 简介1.2 AJAX 优缺点1.3 AJAX 前后端准备1.4 AJAX 请求基本操作1.5 AJAX 发送 POST 请求1.6 设置请求头1.7 响应 JSON 数据1.8 AJAX 请求超时与网络异常处理1.9 取消请求1.10 Fetch 发送 Ajax 请求 2. jQuery-Ajax2.1 jQuery 发送 Ajax 请求&#xff08;G…

2024年11月16日 星期六 重新整理Go技术

今日格言 坚持每天进步一点点~ 一个人也可以是一个团队~ 学习全栈开发, 做自己喜欢的产品~~ 简介 大家好, 我是张大鹏, 今天是2024年11月16日星期六, 很高兴在这里给大家分享技术. 今天又是休息的一天, 做了很多的思考, 整理了自己掌握的技术, 比如Java, Python, Golang,…

炼码LintCode--数据库题库(级别:简单;数量:55道)--刷题笔记_02

目录 炼码LintCode--数据库题库&#xff08;级别&#xff1a;简单&#xff1b;数量&#xff1a;55道&#xff09;--刷题笔记_023618 耗时前三的任务&#xff08;日期差&#xff09;题&#xff1a;sql&#xff1a;解释&#xff1a;DATEDIFF 天数差order by 别名TIMESTAMPDIFF 月…

洛谷刷题日记||基础篇8

#include <iostream> #include <vector> using namespace std;int N, M; // N为行数&#xff0c;M为列数 vector<vector<char>> field; // 表示田地的网格&#xff0c;每个元素是W或. vector<vector<bool>> visited; // 用来记录网格是否访…

在Ubuntu22.04上源码构建ROS noetic环境

Ubuntu22.04上源码构建ROS noetic 起因准备环境创建工作目录并下载源码安装编译依赖包安装ros_comm和rosconsole包的两个补丁并修改pluginlib包的CMakeLists的编译器版本编译安装ROS noetic和ros_test验证 起因 最近在研究VINS-Mono从ROS移植到ROS2&#xff0c;发现在编写feat…