<返回目录     Powered by claude/xia兄

第2课: 核心概念深入解析

深入理解索引、文档、映射和分片机制

🎯 学习目标

📋 前置知识

Index(索引)深入解析

索引是Elasticsearch中最核心的数据组织单位,类似于关系数据库中的数据库。但索引不仅仅是数据容器,它还包含了数据的分片策略、副本配置、映射定义等。

索引的物理结构

每个索引在物理上由多个分片(Shard)组成,每个分片都是一个独立的Lucene索引实例。这种设计使得Elasticsearch能够:

索引命名规范

索引创建示例

# 1. 创建简单索引(使用默认配置)
PUT /products

# 2. 创建带详细配置的索引
PUT /products
{
  "settings": {
    "number_of_shards": 3,        # 主分片数量
    "number_of_replicas": 2,      # 每个主分片的副本数量
    "refresh_interval": "1s",     # 刷新间隔(近实时性)
    "index.max_result_window": 10000  # 最大返回结果数
  },
  "mappings": {
    "properties": {
      "name": { "type": "text" },
      "price": { "type": "float" }
    }
  }
}

# 3. 创建时间序列索引(适合日志数据)
PUT /logs-2024.01.01
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1
  }
}

最佳实践:生产环境应根据数据量和查询负载合理设置分片数量。分片过少会导致性能瓶颈,分片过多会增加管理开销。一般建议每个分片大小在10-50GB之间。

Document(文档)深入解析

文档是Elasticsearch中的基本数据单元,采用JSON格式表示。每个文档都包含元数据和实际数据两部分。

文档结构

文档包含以下核心元数据字段:

文档ID的生成方式

# 1. 自动生成ID(推荐用于日志等场景)
POST /products/_doc
{
  "name": "iPhone 15",
  "price": 5999,
  "category": "手机"
}

# 响应:自动生成ID,如 "_id": "abc123"

# 2. 指定ID(推荐用于业务数据)
PUT /products/_doc/1
{
  "name": "iPhone 15",
  "price": 5999,
  "category": "手机"
}

# 3. 批量操作
POST /_bulk
{ "index": { "_index": "products", "_id": "1" } }
{ "name": "iPhone 15", "price": 5999 }
{ "index": { "_index": "products", "_id": "2" } }
{ "name": "iPad Pro", "price": 7999 }

文档的存储和检索

# 完整的文档示例(包含元数据)
{
  "_index": "products",
  "_id": "1",
  "_version": 1,
  "_seq_no": 0,
  "_primary_term": 1,
  "found": true,
  "_source": {
    "name": "iPhone 15",
    "price": 5999,
    "category": "手机",
    "brand": "Apple",
    "tags": ["智能手机", "苹果"],
    "specifications": {
      "screen": "6.1英寸",
      "memory": "128GB"
    },
    "created_at": "2024-01-01T10:00:00Z"
  }
}

文档大小限制:单个文档大小默认限制为100MB。对于大文档,建议拆分成多个小文档或使用附件处理。

Field(字段)与数据类型深入解析

字段是文档中的键值对,每个字段都有特定的数据类型。正确选择数据类型对搜索性能和存储效率至关重要。

核心数据类型详解

类型 详细说明 适用场景 示例
text 全文本类型,会被分词器处理,支持全文检索 文章内容、商品描述、用户评论 "这是一段需要全文检索的文本"
keyword 精确值类型,不分词,支持精确匹配、聚合、排序 状态码、标签、分类、ID "iPhone"、"ACTIVE"、"user123"
long/integer 整数类型,支持范围查询、聚合 年龄、数量、评分 100、-50、999999
float/double 浮点数类型,支持精确计算 价格、评分、百分比 99.99、3.14159、-45.67
boolean 布尔值类型,支持true/false 开关状态、是否标记 true、false
date 日期类型,支持多种格式和时区 创建时间、更新时间、事件时间 "2024-01-01"、"2024-01-01T10:00:00Z"
geo_point 地理位置类型,支持距离计算 用户位置、商家地址 {"lat": 40.7128, "lon": -74.0060}
ip IP地址类型,支持CIDR查询 用户IP、服务器IP "192.168.1.1"、"::1"
nested 嵌套对象类型,保持数组元素的独立性 订单项、标签数组 [{"name": "tag1"}, {"name": "tag2"}]

text vs keyword 的深入理解

这是Elasticsearch中最容易混淆的两个类型:

# 错误用法:将需要精确匹配的字段设为text类型
PUT /products
{
  "mappings": {
    "properties": {
      "category": { "type": "text" }  # 错误!category应该用keyword
    }
  }
}

# 正确用法:text用于全文检索,keyword用于精确匹配
PUT /products
{
  "mappings": {
    "properties": {
      "title": { "type": "text" },      # 需要全文检索
      "category": { "type": "keyword" }, # 需要精确匹配
      "description": { 
        "type": "text",
        "fields": {
          "keyword": { "type": "keyword" }  # 多字段:同时支持两种方式
        }
      }
    }
  }
}

多字段技巧:对于既需要全文检索又需要精确匹配的字段,可以使用多字段(multi-fields)配置,让一个字段同时具备text和keyword特性。

Mapping(映射)深入解析

映射定义了文档及其字段的存储和索引方式,类似于数据库的表结构。映射决定了字段如何被分析、索引和存储。

映射的类型

动态映射示例

# 1. 动态映射:Elasticsearch自动推断类型
PUT /dynamic_index/_doc/1
{
  "title": "Elasticsearch教程",     # 推断为text
  "price": 99.99,                   # 推断为float
  "category": "技术书籍",            # 推断为text(可能不是最佳选择)
  "published": true,                # 推断为boolean
  "publish_date": "2024-01-01"      # 推断为date
}

# 查看自动生成的映射
GET /dynamic_index/_mapping

显式映射示例

# 2. 显式映射:手动定义最佳类型
PUT /products
{
  "mappings": {
    "properties": {
      "name": { 
        "type": "text",
        "analyzer": "ik_max_word",  # 使用中文分词器
        "search_analyzer": "ik_smart"
      },
      "price": { 
        "type": "float",
        "index": true               # 可被索引(默认)
      },
      "category": { 
        "type": "keyword",
        "ignore_above": 256         # 超过256字符的keyword不会被索引
      },
      "description": { 
        "type": "text",
        "fields": {
          "keyword": { "type": "keyword" }  # 多字段配置
        }
      },
      "created_at": { 
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
      },
      "tags": {
        "type": "nested",           # 嵌套类型,保持数组元素独立性
        "properties": {
          "name": { "type": "keyword" },
          "color": { "type": "keyword" }
        }
      }
    }
  }
}

# 查看映射
GET /products/_mapping

重要提醒:一旦索引创建后,映射中的字段类型通常不能修改。如果需要修改字段类型,需要重新创建索引并重新导入数据。

Elasticsearch与关系数据库的深度对比

理解Elasticsearch与传统关系数据库的区别,有助于正确选择和使用这两种技术。

概念 Elasticsearch 关系数据库(MySQL) 技术差异
数据模型 文档型,Schema-free 关系型,固定Schema Elasticsearch支持动态字段,MySQL需要预定义表结构
查询语言 Query DSL(JSON) SQL Elasticsearch使用领域特定语言,MySQL使用标准SQL
事务支持 有限的事务支持 完整的ACID事务 MySQL适合强一致性场景,Elasticsearch适合搜索分析
扩展性 水平扩展,分布式架构 垂直扩展为主 Elasticsearch天然支持分布式,MySQL扩展复杂
实时性 近实时(1秒内) 实时 MySQL写入后立即可读,Elasticsearch有短暂延迟
全文检索 原生支持,性能优秀 有限支持,性能一般 Elasticsearch基于Lucene,搜索能力远超MySQL
聚合分析 强大的聚合功能 基本的聚合函数 Elasticsearch支持复杂的数据分析和统计

架构选择建议:在实际项目中,通常将Elasticsearch与关系数据库结合使用。关系数据库负责事务处理和核心数据存储,Elasticsearch负责搜索和分析功能。

分片和副本机制深入解析

分片和副本是Elasticsearch分布式架构的核心,理解它们的工作原理对性能优化至关重要。

分片机制详解

分片配置策略

# 1. 默认配置(5个主分片,1个副本)
PUT /default_index

# 2. 自定义分片配置
PUT /custom_index
{
  "settings": {
    "number_of_shards": 3,        # 主分片数量
    "number_of_replicas": 2,      # 每个主分片的副本数量
    "routing.allocation.total_shards_per_node": 10  # 每个节点最大分片数
  }
}

# 3. 查看分片分布
GET /_cat/shards?v&s=node

# 4. 查看分片健康状态
GET /_cat/indices?v&health=red,yellow,green

分片数量选择原则

数据量 建议分片数 说明
< 10GB 1-2个分片 小数据量,避免分片过多增加开销
10GB - 100GB 3-5个分片 中等数据量,平衡性能和开销
100GB - 1TB 5-10个分片 大数据量,支持并行处理
> 1TB 10+个分片 超大数据量,需要水平扩展

分片设计最佳实践:

实践练习

练习1:索引创建与映射配置

创建一个名为"library"的索引,要求:

  1. 设置3个主分片,2个副本
  2. 配置以下字段映射:
    • title:text类型,使用中文分词器
    • author:keyword类型
    • price:float类型
    • publish_date:date类型,支持多种格式
    • isbn:keyword类型,忽略超过20字符的值
    • tags:nested类型,包含name和color字段

练习2:文档操作

  1. 插入5本图书文档(使用自动ID和指定ID两种方式)
  2. 查看插入的文档
  3. 更新其中一本图书的价格
  4. 删除一本图书

练习3:索引管理

  1. 查看索引的映射信息
  2. 查看分片分布情况
  3. 查看索引统计信息
  4. 关闭索引,然后重新打开

常见问题解答

Q: 如何选择text和keyword类型?

A: 如果需要全文检索(如搜索"苹果手机"能匹配到"苹果"和"手机"),使用text类型;如果需要精确匹配(如分类、标签),使用keyword类型。

Q: 分片数量设置多少合适?

A: 一般建议每个分片大小在10-50GB之间。分片过少会导致性能瓶颈,分片过多会增加管理开销。

Q: 映射创建后可以修改吗?

A: 已存在字段的类型不能修改,但可以添加新字段。如果需要修改字段类型,需要重新创建索引。

Q: 什么时候使用nested类型?

A: 当数组中的对象需要保持独立性,并且需要对这些对象进行独立查询时,使用nested类型。

课程总结

本课重点回顾

下节课预告:第3课将深入讲解文档的CRUD操作,包括单文档操作、批量操作、版本控制、乐观并发控制等高级功能。