【Elasticsearch从入门到精通】第41篇:为什么需要搜索引擎——关系数据库的搜索困境

【Elasticsearch从入门到精通】第41篇:为什么需要搜索引擎——关系数据库的搜索困境 上一篇【第40篇】Elasticsearch SQL语法详解——从DDL到复杂查询下一篇【第42篇】Elasticsearch倒排索引原理——Lucene的核心数据结构摘要在信息化时代快速准确地从海量数据中找到所需信息是企业级应用的核心需求。然而关系数据库在全文搜索场景下面临着严重的性能瓶颈——LIKE查询需要全表扫描B-Tree索引无法有效支持多词组合搜索和模糊匹配。本文将从关系数据库的搜索困境出发深入分析LIKE查询的性能问题揭示B-Tree索引在全文搜索中的根本局限系统讲解搜索引擎的三大核心过程分析Analysis、索引Indexing、搜索Searching并阐明搜索引擎索引查找O(logN)相比顺序查找O(N)的性能优势。通过MySQL与ES的性能对比实验帮助读者理解为什么需要引入专门的搜索引擎。一、关系数据库的搜索困境1.1 关系数据库的优势关系数据库如MySQL、PostgreSQL在数据管理方面具有明显优势二维表结构直观贴近逻辑世界易于理解和建模ACID事务支持保证数据一致性和可靠性SQL标准查询支持多表JOIN等复杂关系操作数据更新高效行级锁、MVCC等机制保障并发写入成熟的生态备份、主从复制、分库分表方案成熟这些优势使得关系数据库成为结构化数据管理的首选。然而当面临全文搜索需求时关系数据库的表现却不尽人意。1.2 典型搜索场景考虑一个电商平台的商品搜索场景商品表中有百万级商品记录每个商品包含名称、描述、分类等多个文本字段用户需要通过关键词快速找到相关商品搜索需要支持分词、模糊匹配、相关度排序用户搜索运动鞋 充电宝 期望结果 - 返回名称或描述中包含运动或鞋的商品 - 同时返回包含充电宝的商品 - 按相关度排序二、LIKE查询的性能问题2.1 LIKE ‘%keyword%’ 的执行方式当使用关系数据库的LIKE进行模糊搜索时-- 前缀匹配可以使用B-Tree索引SELECT*FROMproductsWHEREnameLIKE运动鞋%;-- 包含匹配无法使用索引全表扫描SELECT*FROMproductsWHEREnameLIKE%运动鞋%;-- 复杂包含匹配无法使用索引全表扫描SELECT*FROMproductsWHEREdescriptionLIKE%运动鞋%充电宝%;LIKE %运动鞋%的执行过程┌──────────────────────────────────────────────────────┐ │ 全表扫描流程 │ │ │ │ 第1行: 金龙鱼油700ml → 不匹配继续 │ │ 第2行: 华为手机Mate60 → 不匹配继续 │ │ 第3行: 耐克运动鞋Air Max → 匹配 │ │ 第4行: 阿迪达斯跑鞋 → 不匹配继续 │ │ ... │ │ 第N行: 小米充电宝 → 匹配 │ │ 第N1行: ... │ │ │ │ 100万行数据 → 需要逐一检查每一行 │ │ 时间复杂度: O(N) │ └──────────────────────────────────────────────────────┘2.2 性能分析LIKE %keyword%查询的时间复杂度为O(N)即与数据量线性相关数据量预估扫描时间实际表现1万条~10ms勉强可接受10万条~100ms明显卡顿100万条~1s不可接受1000万条~10s完全不可用1亿条~100s系统崩溃即使是LIKE 运动鞋%这种前缀匹配虽然可以使用B-Tree索引也存在以下局限只能匹配单个字段的前缀无法同时搜索多个字段不支持分词“运动鞋不会被拆分为运动和鞋”无法进行相关度排序2.3 实战MySQL EXPLAIN分析创建测试表并插入数据CREATETABLEproducts(idINTPRIMARYKEYAUTO_INCREMENT,nameVARCHAR(255)NOTNULL,descriptionTEXT,categoryVARCHAR(100),priceDECIMAL(10,2),INDEXidx_name(name))ENGINEInnoDB;-- 插入100万条测试数据INSERTINTOproducts(name,description,category,price)SELECTCONCAT(商品-,FLOOR(RAND()*1000000)),CONCAT(这是商品-,FLOOR(RAND()*1000000),的详细描述信息),CASEFLOOR(RAND()*5)WHEN0THEN电子产品WHEN1THEN服装鞋帽WHEN2THEN食品饮料WHEN3THEN家居用品ELSE运动户外END,ROUND(RAND()*1000,2)FROMinformation_schema.columnsaJOINinformation_schema.columnsbLIMIT1000000;执行EXPLAIN分析前缀匹配EXPLAINSELECT*FROMproductsWHEREnameLIKE运动鞋%;---------------------------------------------------------------------------------------------------------- | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | ---------------------------------------------------------------------------------------------------------- | 1 | SIMPLE | products | range | idx_name | idx_name | 768 | NULL | 1 | Using where; Using index | ----------------------------------------------------------------------------------------------------------执行EXPLAIN分析包含匹配EXPLAINSELECT*FROMproductsWHEREnameLIKE%运动鞋%;------------------------------------------------------------------------------------------ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | ------------------------------------------------------------------------------------------ | 1 | SIMPLE | products | ALL | NULL | NULL | NULL | NULL | 998412 | Using where | ------------------------------------------------------------------------------------------可以看到LIKE %运动鞋%的type为ALL全表扫描扫描行数接近全表100万行而key为NULL表示未使用任何索引。三、B-Tree索引的局限3.1 B-Tree索引的工作原理B-Tree平衡多路搜索树是关系数据库最常用的索引结构B-Tree 索引结构示意 [D - J - P] / | \ [A-C] [E-I] [Q-Z] / \ / \ / \ [ABC] [DEF] [GHI] [JKL] [PQR] [STZ] 查找 King D → J → [J-K-L] → 找到 King3次比较O(logN)B-Tree索引在以下场景下非常高效精确匹配WHERE name 运动鞋前缀匹配WHERE name LIKE 运动鞋%范围查询WHERE price BETWEEN 100 AND 500排序操作ORDER BY create_time DESC3.2 B-Tree无法支持全文搜索的根本原因B-Tree索引的构建基于完整的字段值排序这决定了它无法有效支持全文搜索B-Tree 对文本字段建立的索引 节点1: [阿迪达斯跑鞋, 华为手机Mate60, 金龙鱼油700ml] 节点2: [耐克运动鞋Air Max, 小米充电宝20000mAh, 运动鞋套装] ... 查找包含运动的商品 ❌ 运动不是一个完整的索引键无法在B-Tree中定位 ❌ 阿迪达斯跑鞋和耐克运动鞋Air Max都包含运动 但它们在B-Tree中并不相邻 ❌ 必须遍历所有节点逐一比较B-Tree索引的局限总结局限说明无法前缀扫描内部内容B-Tree只能匹配值的开头无法匹配中间部分不支持分词运动鞋不会被拆分为运动和鞋分别索引无法多字段联合搜索跨字段搜索需要建立复合索引灵活性差无相关度排序只能精确匹配或排序无法按匹配程度排序同义词/近义词无法处理搜索手机无法匹配telephone3.3 MySQL全文索引的尝试MySQL提供了FULLTEXT索引作为全文搜索方案ALTERTABLEproductsADDFULLTEXTINDEXft_name_desc(name,description);SELECT*FROMproductsWHEREMATCH(name,description)AGAINST(运动鞋INNATURALLANGUAGEMODE);MySQL全文索引虽然优于LIKE但存在以下不足支持的分词算法有限不支持中文分词需插件不支持复杂的相关度评分算法性能不及专门的搜索引擎缺少分布式能力不支持实时索引更新四、搜索引擎的解决方案4.1 搜索引擎的核心思想搜索引擎解决搜索问题的核心思想是预先提取文档中的关键词建立从关键词到文档的映射索引。传统方式顺序查找 查询运动鞋 → 遍历文档1、文档2、文档3... → 在文档中查找关键词 时间复杂度: O(N) 搜索引擎索引查找 查询运动鞋 → 在索引中查找运动鞋 → 直接获取文档列表 时间复杂度: O(logN)4.2 搜索引擎的三大核心过程过程一分析Analysis分析是将原始文本切分为关键词Term的过程原文: 耐克运动鞋 Air Max 精品推荐 ↓ 分词器 分词结果: [耐克, 运动, 鞋, air, max, 精品, 推荐] ↓ 过滤器 过滤后: [耐克, 运动, 鞋, air, max, 精品, 推荐] ↓ 去停用词、转小写等 最终Term: [耐克, 运动, 鞋, air, max, 精品, 推荐]分析过程的主要组件字符过滤器Character Filter处理HTML标签、特殊字符等分词器Tokenizer将文本切分为词语词项过滤器Token Filter转小写、去停用词、同义词替换、词干提取等过程二索引Indexing索引是将分析后的Term建立倒排索引的过程文档1: 耐克运动鞋精品推荐 文档2: 阿迪达斯运动鞋新款 文档3: 小米充电宝20000mAh 文档4: 运动鞋跑步专用 建立的倒排索引 ┌──────────┬──────────────────────┐ │ Term │ 文档列表(DocID) │ ├──────────┼──────────────────────┤ │ 耐克 │ [1] │ │ 运动 │ [1, 2, 4] │ │ 鞋 │ [1, 2, 4] │ │ 精品 │ [1] │ │ 推荐 │ [1] │ │ 阿迪达斯 │ [2] │ │ 新款 │ [2] │ │ 小米 │ [3] │ │ 充电宝 │ [3] │ │ 跑步 │ [4] │ │ 专用 │ [4] │ └──────────┴──────────────────────┘过程三搜索Searching搜索过程利用倒排索引快速定位文档查询: 运动鞋 步骤1 - 分析: [运动, 鞋] 步骤2 - 查找索引: 运动 → [1, 2, 4] 鞋 → [1, 2, 4] 步骤3 - 合并结果AND关系: [1, 2, 4] ∩ [1, 2, 4] [1, 2, 4] 步骤4 - 相关度排序: 文档1: 耐克运动鞋精品推荐 → 运动和鞋都出现 → 高分 文档4: 运动鞋跑步专用 → 运动和鞋都出现 → 高分 文档2: 阿迪达斯运动鞋新款 → 运动和鞋都出现 → 高分 步骤5 - 返回排序后的结果4.3 性能对比O(logN) vs O(N)操作顺序查找数据库LIKE索引查找搜索引擎查找单个关键词O(N)O(logN)查找多个关键词O(N * M)O(M * logN)100万文档查找~1000ms~1ms1亿文档查找~100000ms~2ms扩展性线性增长对数增长其中N为文档总数M为查询关键词数量。性能对比示意 顺序查找 (O(N)): N1K ██ N10K ██████████ N100K ████████████████████ N1M ██████████████████████████████████ N10M ████████████████████████████████████████████████████ 索引查找 (O(logN)): N1K █ N10K ███ N100K ████ N1M █████ N10M █████ N100M ██████五、Elasticsearch作为搜索分析引擎5.1 ES的定位Elasticsearch不仅仅是一个搜索引擎更是一个分布式搜索与分析引擎能力维度Elasticsearch传统数据库全文搜索核心能力高性能弱LIKE/FULLTEXT实时索引近实时秒级需要重建索引分布式原生分布式水平扩展主从复制垂直扩展分析聚合强大的聚合框架GROUP BY高可用分片副本自动容灾主从切换数据规模PB级TB级5.2 适用场景Elasticsearch特别适合以下场景全文搜索电商商品搜索、文档内容检索日志分析集中式日志管理ELK栈指标监控时序数据分析、实时监控站内搜索网站/App内部搜索数据分析交互式数据探索六、总结与最佳实践核心要点关系数据库不适合全文搜索LIKE %keyword%需要全表扫描性能随数据量线性下降B-Tree索引的局限基于完整值排序无法支持内容中间匹配、分词和多字段联合搜索搜索引擎的核心价值通过倒排索引实现O(logN)的查找性能相比数据库的O(N)有数量级的优势ES的定位是搜索分析不仅是搜索引擎还是强大的分布式分析引擎最佳实践清单结构化数据存储和事务操作使用关系数据库全文搜索、日志分析使用Elasticsearch两者通过数据同步机制如Canal、Logstash配合使用不要试图用数据库替代搜索引擎做全文搜索对于中文搜索务必配置合适的中文分词器如IK Analyzer理解搜索引擎的分析过程合理配置分析器上一篇【第40篇】Elasticsearch SQL语法详解——从DDL到复杂查询下一篇【第42篇】Elasticsearch倒排索引原理——Lucene的核心数据结构