侧边栏壁纸
博主头像
极客手札博主等级

Do everything!

  • 累计撰写 31 篇文章
  • 累计创建 16 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

ES学习

一、Elasticsearch是什么?

  • 定位 :基于 Lucene 的分布式、RESTful 搜索引擎和分析引擎。
  • 核心功能 :快速全文检索、结构化搜索、数据分析、实时日志处理等。
  • 适用场景 :搜索引擎、日志分析(如 ELK Stack)、大数据实时分析、商业智能(BI)等。

二、核心概念

1、 索引(index)

1. 定义

类比 :类似关系型数据库中的“表”,但设计更灵活,适用于非结构化数据。
作用 :存储具有相似结构的文档集合,是数据管理的顶层逻辑单元。

2. 核心特性

  • Mapping(映射)
    定义字段类型(如 text、keyword、integer、geo_point)。
    动态映射 (Dynamic Mapping):ES 自动推断字段类型(例如 "123" 可能被识别为 text 而非 integer)。
    显式映射 (Explicit Mapping):手动定义字段类型和属性(推荐生产环境使用)。
    创建索引:
PUT /my_index
{
  "mappings": {
    "properties": {
      "title": { "type": "text" },     // 全文搜索字段
      "price": { "type": "float" },    // 数值类型,支持过滤和聚合
      "tags":  { "type": "keyword" }   // 精确值匹配(如过滤)
    }
  }
}
  • Settings(设置)
    number_of_shards:主分片数量(索引创建后不可修改)。
    number_of_replicas:每个主分片的副本数量(可动态调整)。
PUT /my_index
{
  "settings": {
    "number_of_shards": 3,    // 将索引分为 3 个主分片
    "number_of_replicas": 1   // 每个主分片有 1 个副本
  }
}

3. 注意事项

  • 分片数规划:分片过少无法扩展写入,分片过多影响性能(建议单分片 10GB~50GB)。
  • 冷热分离:通过索引生命周期管理(ILM)将旧索引迁移到低性能节点。

2、文档(Document)

1. 定义

类比:类似数据库中的“一行记录”,是ES中存储和操作的基本单元。
格式:JSON对象,包含业务数据和元数据。

2. 核心特性

  • 文档必须有_id(可自动生成或手动指定)
  • 元数据字段:
    • _index:所在索引的名称
    • _type:已废弃(ES 7后默认为 _doc)
    • _source:存储原始 JSON,支持检索原始内容
    • _version:版本号,用于乐观锁控制
PUT /my_index/_doc/1    // 手动指定 _id=1
{
  "title": "Elasticsearch Guide",
  "price": 49.99,
  "tags": ["search", "database"]
}

3. 操作类型

  • Create :指定 _id 写入新文档(若 _id 存在则报错)。
  • Index :覆盖写入(不存在则创建,存在则替换)。
  • Update :局部更新(部分字段修改)。
  • Delete:删除文档

3、节点(Node)与集群(Cluster)

1. 节点(Node)

  • 定义 :单个 ES 服务实例,通常是物理机或虚拟机上的一个进程。
  • 核心角色 :
    • 主节点(Master Node) :管理集群状态(如索引增删、节点加入)、不处理用户请求。
    • 数据节点(Data Node) :存储分片数据、执行 CRUD 和搜索操作。
    • 协调节点(Coordinating Node) :接收客户端请求,将请求路由到相关节点并聚合结果(默认所有节点均为此角色)。
    • 专用节点 :如 Ingest Node(数据预处理)、Machine Learning Node。
# 配置文件 elasticsearch.yml
node.master: true    # 是否可作为主节点
node.data: false     # 不作为数据节点(专用主节点)

2. 集群(Cluster)

  • 定义 :多个节点协同工作的集合,对外提供统一的搜索服务。
  • 核心特性 :
    • 高可用 :节点故障时,副本分片自动晋升为主分片。
    • 负载均衡 :请求由协调节点分发到各数据节点。
    • 发现机制 :节点通过 Zen Discovery 或 gossip 协议(7.x 后版本支持)自动加入集群。

4、分片(Shard)与副本(Replica)

1. 分片(Shard)

  • 定义 :索引被水平切分为多个子集,每个分片是一个独立的 Lucene 索引。
  • 核心作用 :
    • 横向扩展 :分片可分布在多个节点上,利用多机资源提升性能。
    • 并行处理 :搜索和聚合操作在各分片上并行执行。

2. 副本(Replica)

  • 定义 :主分片的完整拷贝,仅用于读取操作(不可写入)。
  • 核心作用 :
    • 高可用 :主分片故障时,副本分片自动接管。
    • 负载均衡 :查询请求可路由到主分片或副本,提升吞吐量。

3. 配置实例

PUT /my_index
{
  "settings": {
    "number_of_shards": 3,    // 主分片数为 3
    "number_of_replicas": 1   // 每个主分片有 1 个副本
  }
}
  • 分片分配逻辑 :
    • 假设集群有 2 个数据节点,3 个主分片 + 3 个副本分片会被分配如下:
    Node1: Shard0 (Primary), Shard1 (Replica), Shard2 (Replica)
    Node2: Shard1 (Primary), Shard2 (Primary), Shard0 (Replica)
    
    • 若新增节点,ES 会自动调整分片分布以均衡负载。

4. 注意事项

  • 分片数 :创建索引时需合理规划,后续无法修改(需通过 Reindex API 迁移数据)。
  • 副本数 :可动态调整,例如临时关闭副本以提升写入性能:
PUT /my_index/_settings
{
  "index.number_of_replicas": 0
}

5、映射(Mapping)与动态特性

1. 映射的作用

定义索引中每个字段的数据类型和属性(如是否允许全文搜索、是否参与聚合)。

2. 动态映射的潜在问题

类型错误 :例如将 "2023-10-01" 自动推断为 text 而非 date,导致无法进行时间范围查询。
解决方案 :提前定义显式映射(尤其是生产环境)。

3. 核心字段类型

text:全文检索字段(会被分词,如“Quick Brown”分为 Quick 和 Brown)。
keyword:精确值字段(用于过滤、聚合、排序,如 status 值 published)。
nested:嵌套对象(解决数组字段的扁平化问题)。

三、架构及原理

1、 近实时(NRT,Near Real-Time)

核心机制 :

  • 写入流程 :文档并非直接写入磁盘,而是先存到内存的 Buffer 中,随后写入 Translog (事务日志,用于故障恢复)。
  • Refresh 操作 :Buffer 按默认间隔 1秒 将数据刷新到 Lucene 的 Segment (不可变的索引段),此时文档可被检索。
  • Flush 操作 :定期(默认每 30 分钟或 Translog 大小达到阈值)将 Segment 写入磁盘并清空 Translog。

NRT 的意义 :

  • 权衡 写入速度 与 数据可见性 :内存 Buffer 减少磁盘 I/O,1秒 延迟是可配置的(通过 refresh_interval 参数)。
  • 潜在问题 :在 Refresh 前发生宕机时,依赖 Translog 恢复未持久化的数据。

配置示例 :

# 修改索引的刷新间隔为 5 秒
PUT /my_index/_settings
{
  "index": { "refresh_interval": "5s" }
}

2、 倒排索引(Inverted Index)

核心结构 :

  • 正排索引(Forward Index) :传统数据库模式,通过 ID 找到文档内容。
  • 倒排索引(Inverted Index) :
    • 词项(Term) :分词后的最小单元(如 "elastic"、"search")。
    • 映射表(Postings List) :记录词项出现过的文档 ID(如 "elastic" → [Doc1, Doc3])。
    • 词频(TF)与位置(Position) :支持相关性评分和短语查询。

高效搜索的原因 :

  • 直接通过词项定位文档,避免全表扫描。
  • 结合 压缩算法 (如 FST)减少内存占用,提升检索速度。

示例

假设两篇文档:
- Doc1: "Elasticsearch is fast"
- Doc2: "Search is powerful"
倒排索引生成:

Term | Documents
elastic → [Doc1]
search → [Doc1, Doc2]
fast → [Doc1]
powerful → [Doc2]

3、 分布式协调

1. 节点角色 :

  • Master Node :负责集群状态管理(如索引创建/删除、节点加入/离开)。
  • Data Node :存储分片数据,执行 CRUD 和搜索操作。
  • Coordinating Node (默认所有节点):接受客户端请求并路由到正确节点。

2. 集群发现机制(Zen Discovery) :

  • 早期版本 :基于 Gossip 协议和选举算法(如 Bully Algorithm)。
  • 7.x 版本后 :改用 Raft 协议 ,提升选举效率和一致性。
  • 分片分配策略 :
    主分片 (Primary Shard)负责写入,副本分片(Replica)同步数据。
    默认动态均衡分片位置,避免单点故障。

3. 故障恢复流程 :

  • 节点宕机:Master 节点检测到节点失联(默认 3 次 ping 失败)。
  • 分片重新分配:将宕机节点的分片副本提升为主分片,或在其他节点重建副本。

四、核心功能

1、全文检索

get /my_index/_search

1. match查询

match 查询是 Elasticsearch 中最常用的查询类型之一,它会根据查询条件查找包含关键词的文档。

{
  "query": {
    "match": {
      "field_name": "search_term"
    }
  }
}
  • 示例:查询 title 字段包含关键词 “Elasticsearch” 的文档:
{
  "query": {
    "match": {
      "title": "Elasticsearch"
    }
  }
}

2. Term 查询

term 查询用于精确匹配,不会对查询词进行分析(不进行分词处理),适用于数字、关键词等字段。

{
  "query": {
    "term": {
      "field_name": "exact_value"
    }
  }
}
  • 示例:查询 status 字段为 active 的文档:
{
  "query": {
    "term": {
      "status": "active"
    }
  }
}

3. Range 查询

range 查询用于查找在指定范围内的文档,通常用于数值、日期等字段。

{
  "query": {
    "range": {
      "field_name": {
        "gte": "lower_bound",
        "lte": "upper_bound"
      }
    }
  }
}
  • 示例:查询 age 字段在 20 到 30 之间的文档:
{
  "query": {
    "range": {
      "age": {
        "gte": 20,
        "lte": 30
      }
    }
  }
}

4. Bool查询

bool 查询用于组合多个查询条件,可以使用 must(必须满足)、should(可以满足)、must_not(不能满足)等逻辑操作符。

{
  "query": {
    "bool": {
      "must": [
        { "match": { "field_name1": "value1" } },
        { "match": { "field_name2": "value2" } }
      ],
      "filter": [
        { "range": { "field_name3": { "gte": "value3" } } }
      ]
    }
  }
}
  • 示例:查询 title 包含 “Elasticsearch” 且 age 大于 25 的文档:
{
  "query": {
    "bool": {
      "must": [
        { "match": { "title": "Elasticsearch" } }
      ],
      "filter": [
        { "range": { "age": { "gte": 25 } } }
      ]
    }
  }
}

5. Wildcard 查询

wildcard查询用于基于模式匹配的搜索,可以使用*来代表任意字符,?代表一个字符。

{
  "query": {
    "wildcard": {
      "field_name": "pattern"
    }
  }
}
  • 示例:查询 username 字段以 “user” 开头的文档:
{
  "query": {
    "wildcard": {
      "username": "user*"
    }
  }
}

6. Fuzzy查询

fuzzy 查询用于执行模糊匹配,适用于搜索具有相似拼写的词。

{
  "query": {
    "fuzzy": {
      "field_name": {
        "value": "search_term",
        "fuzziness": "AUTO"
      }
    }
  }
}
  • 示例:查询 name 字段模糊匹配 “Elasitcsearch” 的文档:
{
  "query": {
    "fuzzy": {
      "name": {
        "value": "Elasitcsearch",
        "fuzziness": "AUTO"
      }
    }
  }
}

7. Match All 查询

match_all 查询会返回索引中的所有文档,通常用于获取所有数据。

{
  "query": {
    "match_all": {}
  }
}

8. Highlight 查询

highlight 用于高亮显示查询匹配的部分,在查询结果中突出显示相关字段。

{
  "query": {
    "match": {
      "field_name": "search_term"
    }
  },
  "highlight": {
    "fields": {
      "field_name": {}
    }
  }
}

9. Prefix 查询

prefix 查询用于查找字段值以特定前缀开头的文档。

{
  "query": {
    "prefix": {
      "field_name": "prefix_value"
    }
  }
}

2、Aggregation(聚合)分析

指标计算(Metrics Aggregations)

聚合用于对数据进行分组或汇总,常用于统计分析。

avg:计算某个字段的平均值

GET /products/_search
{
  "size": 0,
  "aggs": {
    "avg_price": {
      "avg": {
        "field": "price"
      }
    }
  }
}

解释:计算 price 字段的平均值。

sum:计算某个字段的总和

GET /products/_search
{
  "size": 0,
  "aggs": {
    "total_sales": {
      "sum": {
        "field": "sales"
      }
    }
  }
}

解释:计算 sales 字段的总和。

max / min:计算某个字段的最大值/最小值

GET /products/_search
{
  "size": 0,
  "aggs": {
    "max_price": {
      "max": {
        "field": "price"
      }
    },
    "min_price": {
      "min": {
        "field": "price"
      }
    }
  }
}

解释:分别计算 price 字段的最大值和最小值。

cardinality:计算某个字段的去重值数量

GET /products/_search
{
  "size": 0,
  "aggs": {
    "unique_categories": {
      "cardinality": {
        "field": "category"
      }
    }
  }
}

解释:计算 category 字段中不同(去重后的)值的数量,相当于 SQL 中的 COUNT(DISTINCT)。

分组(Bucket Aggregations)

这些聚合根据某个字段的值将文档分成不同的“桶”,如按类别、时间或数值范围进行分组。

terms:按字段值分组

GET /products/_search
{
  "size": 0,
  "aggs": {
    "category_groups": {
      "terms": {
        "field": "category"
      }
    }
  }
}

解释:将文档按 category 字段的值分组,返回每个类别及其文档数量。

date_histogram:按时间间隔分组(如按天分组)

GET /products/_search
{
  "size": 0,
  "aggs": {
    "daily_sales": {
      "date_histogram": {
        "field": "timestamp",
        "calendar_interval": "day"
      },
      "aggs": {
        "total_sales": {
          "sum": {
            "field": "sales"
          }
        }
      }
    }
  }
}

解释:将文档按 timestamp 字段按天分组,并计算每一天的 sales 总和。

range:按数值范围分组

GET /products/_search
{
  "size": 0,
  "aggs": {
    "price_ranges": {
      "range": {
        "field": "price",
        "ranges": [
          { "to": 100 },
          { "from": 100, "to": 500 },
          { "from": 500 }
        ]
      }
    }
  }
}

解释:将文档根据 price 字段的值分为三个区间:小于 100、100 到 500 之间、大于 500。

管道聚合(Pipeline Aggregations)

作用 :基于其他聚合结果进一步计算(如计算每个月的增长率)。

derivative:计算导数(如计算增长率)

GET /products/_search
{
  "size": 0,
  "aggs": {
    "daily_sales": {
      "date_histogram": {
        "field": "timestamp",
        "calendar_interval": "day"
      },
      "aggs": {
        "total_sales": {
          "sum": {
            "field": "sales"
          }
        },
        "sales_derivative": {
          "derivative": {
            "buckets_path": "total_sales"
          }
        }
      }
    }
  }
}

解释:先按天分组计算每一天的 sales 总和,然后计算每天销售总和的增长(即每一天与前一天的差异,类似于增长率)。

moving_avg:计算移动平均

GET /products/_search
{
  "size": 0,
  "aggs": {
    "daily_sales": {
      "date_histogram": {
        "field": "timestamp",
        "calendar_interval": "day"
      },
      "aggs": {
        "total_sales": {
          "sum": {
            "field": "sales"
          }
        },
        "sales_moving_avg": {
          "moving_avg": {
            "buckets_path": "total_sales",
            "window": 7,
            "model": "simple"
          }
        }
      }
    }
  }
}

解释:先按天分组计算 sales 总和,然后计算该总和的 7 天简单移动平均。

bucket_script:跨桶计算

GET /products/_search
{
  "size": 0,
  "aggs": {
    "category_groups": {
      "terms": {
        "field": "category"
      },
      "aggs": {
        "average_price": {
          "avg": {
            "field": "price"
          }
        },
        "price_to_sales_ratio": {
          "bucket_script": {
            "buckets_path": {
              "avg_price": "average_price",
              "total_sales": "total_sales"
            },
            "script": "params.avg_price / params.total_sales"
          }
        }
      }
    }
  }
}

解释:在每个类别下,首先计算 price 字段的平均值,然后通过 bucket_script 聚合计算价格与销售总和的比值(比如价格与销售的比率)。

0

评论区