Go工程师体系课 009【学习笔记】

其它一些功能

  • 个人中心
  • 收藏
  • 管理收货地址(增删改查)
  • 留言

拷贝inventory_srv--> userop_srv 查询替换所有的inventory

Elasticsearch 深度解析文档

1. 什么是Elasticsearch

Elasticsearch是一个基于Apache Lucene构建的分布式、RESTful搜索和分析引擎,能够快速地存储、搜索和分析海量数据。它是Elastic Stack(原ELK Stack)的核心组件。

2. MySQL搜索面临的问题 - 深度剖析

2.1 性能低下问题详解

问题现象:

-- 当数据量达到100万条时,以下查询可能需要数秒
SELECT * FROM products WHERE name LIKE '%手机%' OR description LIKE '%手机%';

性能对比数据:

数据量级 MySQL LIKE查询 Elasticsearch全文搜索 性能提升
1万条 50ms 10ms 5倍
10万条 500ms 15ms 33倍
100万条 5000ms 20ms 250倍
1000万条 50000ms+ 30ms 1600倍+

根本原因:

  1. 全表扫描:LIKE '%keyword%' 无法使用B+树索引,必须扫描所有行
  2. I/O密集:每次查询都需要从磁盘读取大量数据
  3. CPU密集:对每一行数据进行字符串匹配运算
  4. 内存压力:大量数据加载到内存进行处理

实际案例:

某电商平台商品表有500万条记录,使用MySQL模糊查询搜索"苹果手机":
- 查询时间:8.3秒
- CPU使用率:飙升至85%
- 并发10个查询时,响应时间增长到30秒以上

2.2 没有相关性排名问题详解

MySQL查询结果的痛点:

-- MySQL只能按固定规则排序
SELECT * FROM products
WHERE name LIKE '%手机%'
ORDER BY price DESC;  -- 只能按价格、时间等字段排序

Elasticsearch的相关性评分机制:

搜索词:"小米手机"

相关性评分计算:
┌─────────────────────────────────────┐
│ 文档1:"小米手机12 Pro"              │
│ • 词频(TF):2个关键词都出现           │
│ • 逆文档频率(IDF):计算词的稀有度      │
│ • 字段长度:标题较短,权重更高         │
│ • 评分:9.8                         │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│ 文档2:"这是一款性价比很高的手机"      │
│ • 词频(TF):只有"手机"出现            │
│ • 逆文档频率(IDF):"手机"较常见        │
│ • 字段长度:描述较长,权重降低         │
│ • 评分:3.2                         │
└─────────────────────────────────────┘

相关性因素详解:

  1. TF(词频):关键词在文档中出现的频率
  2. IDF(逆文档频率):关键词在所有文档中的稀有程度
  3. 字段长度归一化:短字段中的匹配比长字段权重更高
  4. 字段权重boost:可以设置标题比内容更重要
  5. 查询时权重:可以指定某些查询词更重要

2.3 无法全文搜索问题详解

MySQL全文索引的局限:

-- MySQL全文索引创建
ALTER TABLE products ADD FULLTEXT(name, description);

-- 问题1:最小词长限制(默认4个字符)
-- "手机" 可以搜索,但 "机" 搜不到

-- 问题2:中文分词支持差
-- "苹果手机" 被当作一个整体,搜索"苹果"找不到

Elasticsearch全文搜索能力:

// ES的分析过程示例
输入文本:"我想买一台苹果手机"

分词结果:
[我] [想] [买] [一台] [苹果] [手机] [苹果手机]

同义词扩展:
[苹果] → [Apple, iPhone]
[手机] → [手机, 电话, mobile]

拼写纠错:
"苹果手击" → 建议 "苹果手机"

2.4 搜索不准确、没有分词问题详解

MySQL字符串匹配的问题:

-- 搜索"笔记本"
SELECT * FROM products WHERE name LIKE '%笔记本%';
-- 结果:能找到"笔记本电脑"
-- 问题:找不到"笔记 本子"、"notebook"、"手提电脑"

Elasticsearch智能分词过程:

原始文本:"ThinkPad X1 Carbon超轻薄笔记本电脑"

标准分词器:
[ThinkPad] [X1] [Carbon] [超轻薄] [笔记本] [电脑]

IK分词器(中文):
[ThinkPad] [X1] [Carbon] [超] [轻薄] [超轻薄]
[笔记] [本] [笔记本] [电脑] [笔记本电脑]

拼音分词器:
[si] [kao] [pad] → 可以通过拼音搜索

N-gram分词:
[Thi] [hin] [ink] [nkP] → 支持部分匹配

3. 什么是全文搜索 - 核心原理解析

3.1 结构化数据 vs 非结构化数据

结构化数据(MySQL存储方式):
┌──────┬────────┬────────┬────────┐
│  ID  │  Name  │ Price  │ Stock  │
├──────┼────────┼────────┼────────┤
│  1   │iPhone  │ 5999   │  100   │
│  2   │ 小米   │ 2999   │  200   │
└──────┴────────┴────────┴────────┘

非结构化数据(文本内容):
"这款iPhone手机采用A15处理器,性能强劲,
拍照效果出色,续航能力提升20%,
用户评价:'太棒了,物超所值!'"

3.2 倒排索引原理详解

正排索引(MySQL):

文档ID → 内容
Doc1 → "小米手机"
Doc2 → "苹果手机"
Doc3 → "小米电视"

倒排索引(Elasticsearch):

词项 → 文档列表
"小米" → [Doc1, Doc3]
"手机" → [Doc1, Doc2]
"苹果" → [Doc2]
"电视" → [Doc3]

搜索"小米手机":
1. 查找"小米" → 得到 [Doc1, Doc3]
2. 查找"手机" → 得到 [Doc1, Doc2]
3. 计算交集 → Doc1(最相关)

3.3 倒排索引的详细结构

完整的倒排索引结构:

词项:"手机"
├── 文档频率(DF):1000个文档包含此词
├── 倒排列表:
│   ├── Doc1:
│   │   ├── 词频(TF):3次
│   │   ├── 位置:[5, 28, 102]
│   │   └── 字段:[title, description]
│   ├── Doc2:
│   │   ├── 词频(TF):1次
│   │   ├── 位置:[15]
│   │   └── 字段:[title]
│   └── ...
└── 统计信息:最高词频、平均词频等

4. Elasticsearch架构详解

4.1 集群架构

Elasticsearch集群架构图:

┌─────────────── ES Cluster ──────────────┐
│                                         │
│  ┌─────────────────────────────────┐   │
│  │     Master Node (主节点)         │   │
│  │  • 集群管理                      │   │
│  │  • 索引创建/删除                 │   │
│  │  • 分片分配                      │   │
│  └─────────────────────────────────┘   │
│                                         │
│  ┌──────────┐  ┌──────────┐           │
│  │ Data     │  │ Data     │           │
│  │ Node 1   │  │ Node 2   │           │
│  │ ┌──────┐ │  │ ┌──────┐ │           │
│  │ │ P0   │ │  │ │ R0   │ │           │
│  │ ├──────┤ │  │ ├──────┤ │           │
│  │ │ R1   │ │  │ │ P1   │ │           │
│  │ └──────┘ │  │ └──────┘ │           │
│  └──────────┘  └──────────┘           │
│                                         │
│  P = Primary Shard (主分片)            │
│  R = Replica Shard (副本分片)          │
└─────────────────────────────────────────┘

4.2 数据写入流程

写入流程详解:

客户端 → 协调节点 → 主分片 → 副本分片

1. 客户端发送写请求
   ↓
2. 协调节点通过hash路由确定分片
   ↓
3. 请求转发到主分片节点
   ↓
4. 主分片写入成功
   ↓
5. 并行复制到副本分片
   ↓
6. 所有副本确认
   ↓
7. 返回成功响应给客户端

时间线:
T0 ──→ T1 ──→ T2 ──→ T3 ──→ T4
接收   路由   主分片  副本   响应

4.3 查询流程

查询执行过程:

Phase 1: Query(查询阶段)
┌─────────────────────────────────┐
│ 协调节点向所有分片发送查询请求   │
│ 每个分片返回Top N的文档ID和分数  │
└─────────────────────────────────┘
           ↓
Phase 2: Fetch(获取阶段)
┌─────────────────────────────────┐
│ 协调节点整合所有结果并排序       │
│ 获取最终需要的文档完整内容       │
└─────────────────────────────────┘

5. Elasticsearch核心功能详解

5.1 查询类型详解

// 1. Match查询 - 全文搜索
{
  "query": {
    "match": {
      "title": {
        "query": "苹果手机",
        "operator": "and"  // 必须包含所有词
      }
    }
  }
}

// 2. Term查询 - 精确匹配
{
  "query": {
    "term": {
      "category.keyword": "手机"  // 不分词,精确匹配
    }
  }
}

// 3. Range查询 - 范围查询
{
  "query": {
    "range": {
      "price": {
        "gte": 1000,
        "lte": 5000
      }
    }
  }
}

// 4. Bool复合查询
{
  "query": {
    "bool": {
      "must": [
        {"match": {"title": "手机"}}
      ],
      "filter": [
        {"range": {"price": {"lte": 5000}}}
      ],
      "should": [
        {"match": {"brand": "苹果"}}  // 加分项
      ],
      "must_not": [
        {"term": {"status": "discontinued"}}
      ]
    }
  }
}

5.2 聚合分析功能

// 销售数据分析示例
{
  "aggs": {
    "sales_per_category": {
      "terms": {
        "field": "category"
      },
      "aggs": {
        "avg_price": {
          "avg": {
            "field": "price"
          }
        },
        "total_sales": {
          "sum": {
            "field": "sales_count"
          }
        },
        "price_ranges": {
          "range": {
            "field": "price",
            "ranges": [
              {"to": 1000},
              {"from": 1000, "to": 5000},
              {"from": 5000}
            ]
          }
        }
      }
    }
  }
}

6. 实际应用案例分析

6.1 电商搜索优化案例

某电商平台搜索优化前后对比:

指标 MySQL方案 Elasticsearch方案 改善效果
平均搜索耗时 2.3秒 0.05秒 46倍提升
搜索准确率 65% 92% 提升27%
零结果率 18% 3% 降低15%
服务器数量 8台 3台 节省62.5%成本
并发能力 100 QPS 5000 QPS 50倍提升

实施细节:

  1. 数据同步架构:
    MySQL(主数据) → Binlog → Logstash → Elasticsearch

    定时全量同步(每晚)
  2. 搜索优化策略:
  3. 拼音搜索:支持 "pinguo" 搜索到 "苹果"
  4. 同义词:配置 "手机"、"电话"、"mobile" 为同义词
  5. 搜索建议:实时提示用户可能的搜索词
  6. 纠错功能:自动纠正常见拼写错误

6.2 日志分析系统案例

某互联网公司日志分析系统:

日志处理流程:

应用服务器 → Filebeat → Logstash → Elasticsearch → Kibana
     ↓           ↓          ↓            ↓            ↓
   产生日志    收集      处理转换      存储索引     可视化展示

处理规模:
• 日志量:每天100GB
• 日志条数:10亿条/天
• 查询响应:毫秒级
• 保存周期:30天热数据,1年冷数据

7. 性能优化最佳实践

7.1 索引设计优化

// 优化的Mapping设计
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart",
        "fields": {
          "keyword": {
            "type": "keyword"  // 支持精确匹配
          },
          "pinyin": {
            "type": "text",
            "analyzer": "pinyin"  // 支持拼音搜索
          }
        }
      },
      "price": {
        "type": "scaled_float",
        "scaling_factor": 100  // 价格精度优化
      },
      "category": {
        "type": "keyword"  // 分类不需要分词
      },
      "description": {
        "type": "text",
        "analyzer": "ik_smart"
      },
      "created_time": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss||epoch_millis"
      }
    }
  }
}

7.2 查询性能优化技巧

  1. 使用Filter代替Query(当不需要评分时)
    ```json
    // 优化前:使用query(计算评分)
    {"query": {"term": {"status": "active"}}}

// 优化后:使用filter(不计算评分,可缓存)
{"query": {"bool": {"filter": {"term": {"status": "active"}}}}}
<ol>
<li><strong>合理设置分片数量</strong>

分片数量参考公式:
分片数 = 数据量(GB) / 30GB

示例:
- 100GB数据:3-4个分片
- 1TB数据:35-40个分片
```

  1. 批量操作优化
    json
    // 使用bulk API批量索引
    POST _bulk
    {"index": {"_index": "products", "_id": 1}}
    {"name": "iPhone", "price": 5999}
    {"index": {"_index": "products", "_id": 2}}
    {"name": "小米", "price": 2999}

8. Elasticsearch vs 传统数据库

8.1 适用场景对比

场景 MySQL Elasticsearch 推荐选择
全文搜索 ❌ 差 ✅ 优秀 ES
事务支持 ✅ 完整ACID ❌ 无事务 MySQL
实时统计分析 ⚠️ 一般 ✅ 优秀 ES
关系查询 ✅ 优秀 ❌ 有限 MySQL
地理位置搜索 ❌ 差 ✅ 优秀 ES
日志分析 ❌ 不适合 ✅ 专长 ES
精确数值计算 ✅ 精确 ⚠️ 近似 MySQL

8.2 混合架构方案

推荐的混合架构:

        用户请求
           ↓
    ┌──────────────┐
    │   应用层     │
    └──────────────┘
           ↓
    ┌──────────────────────────┐
    │      搜索请求  → ES       │
    │      事务操作  → MySQL    │
    │      缓存     → Redis    │
    └──────────────────────────┘

数据同步:
MySQL(写) → Binlog → Canal/Debezium → Kafka → ES(读)

9. 常见问题与解决方案

9.1 数据一致性问题

问题: MySQL和ES数据不一致

解决方案:
1. 双写策略:同时写MySQL和ES,使用消息队列保证最终一致性
2. CDC(Change Data Capture):通过Binlog实时同步
3. 定期校验:定时任务对比数据差异并修复

9.2 深度分页问题

问题: 查询第10000页数据时性能极差

解决方案:

// 1. 使用search_after(推荐)
{
  "size": 10,
  "sort": [{"_id": "asc"}],
  "search_after": [10000]  // 上一页最后一个文档的sort值
}

// 2. 使用scroll API(适合导出)
POST /products/_search?scroll=1m
{
  "size": 100,
  "query": {"match_all": {}}
}

10. 总结

Elasticsearch通过倒排索引、分布式架构和强大的全文搜索能力,完美解决了传统数据库在搜索场景下的各种问题。合理使用Elasticsearch可以:

  1. 提升搜索性能:从秒级降到毫秒级
  2. 改善搜索质量:通过相关性评分和智能分词
  3. 支持复杂分析:实时聚合和统计分析
  4. 降低运维成本:更少的服务器,更高的效率

但需要注意的是,Elasticsearch不是MySQL的替代品,而是补充。在实际项目中,应该根据具体场景选择合适的存储方案,通常采用MySQL+Elasticsearch的混合架构能够发挥各自优势。

主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://joyjs.cn/archives/4782

(0)
Walker的头像Walker
上一篇 2025年11月24日 01:00
下一篇 2025年3月8日 12:39

相关推荐

  • 深入理解ES6 006【学习笔记】

    Symbol和Symbol属性 第6种原始数据类型:Symbol。私有名称原本是为了让开发者们创建非字符串属性名称而设计的,但是一般的技术无法检测这些属性的私有名称 创建Symbol let firstName = Symbol(); let person = {} person[firstName] = "Nicholas"; cons…

    个人 2025年3月8日
    1.1K00
  • TS珠峰 003【学习笔记】

    装饰器 // 装饰器 // 只能在类中使用(类本身,类成员使用) // 装饰器,类的装饰器,属性装饰器,访问装饰器 参数装饰器 // 1. 类型装饰器 给类进行扩展,也可以返回一个子类 // 先要在tsconfig.json中开启experimentalDecorators const classDecorator1 = <T extends new …

    个人 2025年3月27日
    1.2K00
  • 深入理解ES6 010【学习笔记】

    改进的数组功能 new Array()的怪异行为,当构造函数传入一个数值型的值,那么数组的length属性会被设为该值;如果传入多个值,此时无论这些值是不是数值型的,都会变为数组的元素。这个特性另人困惑,你不可能总是注意传入数据的类型,所以存在一定的风险。 Array.of() 无论传多少个参数,不存在单一数值的特例(一个参数且数值型),总是返回包含所有参数…

    个人 2025年3月8日
    1.0K00
  • Go工程师体系课 005【学习笔记】

    微服务开发 创建一个微服务项目,所有的项目微服务都在这个项目中进行,创建joyshop_srv,我们无创建用户登录注册服务,所以我们在项目目录下再创建一个目录user_srv 及user_srv/global(全局的对象新建和初始化)user_srv/handler(业务逻辑代码)user_srv/model(用户相关的 model)user_srv/pro…

    个人 2025年11月25日
    4400
  • Go工程师体系课 protobuf_guide【学习笔记】

    Protocol Buffers 入门指南 1. 简介 Protocol Buffers(简称 protobuf)是 Google 开发的一种语言无关、平台无关、可扩展的结构化数据序列化机制。与 JSON、XML 等序列化方式相比,protobuf 更小、更快、更简单。 项目主页:https://github.com/protocolbuffers/prot…

    个人 2025年11月25日
    1.1K00

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
欢迎🌹 Coding never stops, keep learning! 💡💻 光临🌹