1
0
mirror of https://github.com/chai2010/advanced-go-programming-book.git synced 2025-05-28 07:22:20 +00:00
advanced-go-programming-book/ch6-cloud/ch6-x-dist-search-engine.md
2018-07-11 11:27:14 +08:00

6.8 KiB
Raw Blame History

6.x. 分布式搜索引擎

在 web 一章中,我们提到 MySQL 很脆弱。数据库系统本身要保证实时和强一致性,所以其功能设计上都是为了满足这种一致性需求。比如 write ahead log 的设计,基于 B+ 树实现的索引和数据组织,以及基于 MVCC 实现的事务等等。

关系型数据库一般被用于实现 OLTP 系统,所谓 OLTP援引 wikipedia:

在线交易处理OLTP, Online transaction processing是指透过信息系统、电脑网络及数据库以线上交易的方式处理一般即时性的作业数据和更早期传统数据库系统大量批量的作业方式并不相同。OLTP通常被运用于自动化的数据处理工作如订单输入、金融业务…等反复性的日常性交易活动。和其相对的是属于决策分析层次的联机分析处理OLAP

在互联网的业务场景中,也有一些实时性要求不高(可以接受多 s 的延迟),但是查询复杂性却很高的场景。举个例子,在电商的 wms 系统中,或者在大多数业务场景丰富的 crm 或者客服系统中,可能需要提供几十个字段的随意组合查询功能。这种系统的数据维度天生众多,比如一个电商的 wms 中对一件货物的描述,可能有下面这些字段:

仓库 id入库时间库位分区 id储存货架 id入库操作员 id出库操作员 id库存数量过期时间sku 类型,产品品牌,产品分类,内件数量

除了上述信息,如果商品在仓库内有流转。可能还有有关联的流程 id当前的流转状态等等。

想像一下,如果我们所经营的是一个大型电商,每天有千万级别的订单,那么在这个数据库中查询和建立合适的索引都是一件非常难的事情。

在 CRM 或客服类系统中,常常有根据关键字进行搜索的需求,大型互联网公司每天会接收数以万计的用户投诉。而考虑到事件溯源,用户的投诉至少要存 2~3 年。又是千万级甚至上亿的数据。根据关键字进行一次 like 查询,可能整个 MySQL 就直接挂掉了。

这时候我们就需要搜索引擎来救场了。

搜索引擎

elasticsearch 是开源分布式搜索引擎的霸主,其依赖于 Lucene 实现,在部署和运维方面做了很多优化。当今搭建一个分布式搜索引擎比起 Sphinx 的时代已经是容易很多很多了。只要简单配置客户端 ip 和端口就可以了。

虽然 es 是针对搜索场景来订制的,但如前文所言,实际应用中常常用 es 来作为 database 来使用,就是因为倒排列表的特性。可以用比较朴素的观点来理解倒排索引:

┌─────────────────┐       ┌─────────────┬─────────────┬─────────────┬─────────────┐                                          
│  order_id: 103  │──────▶│ doc_id:4231 │ doc_id:4333 │ doc_id:5123 │ doc_id:9999 │                                          
└─────────────────┘       └─────────────┴─────────────┴─────────────┴─────────────┘                                          
                                                                                                                             
                                                                                                                             
                                                                                                                             
                                                                                                                             
                                                                                                                             
┌─────────────────┐       ┌─────────────┬─────────────┬─────────────┬─────────────┬─────────────┐                            
│  sku_id: 30221  │──────▶│ doc_id:4231 │ doc_id:5123 │ doc_id:5644 │ doc_id:7801 │ doc_id:9999 │                            
└─────────────────┘       └─────────────┴─────────────┴─────────────┴─────────────┴─────────────┘                            
                                                                                                                             
                                                                                                                             
                                                                                                                             
                                                                                                                             
┌─────────────────┐       ┌─────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────┐
│   city_id: 3    │──────▶│ doc_id:5123 │ doc_id:9999 │doc_id:10232 │doc_id:54321 │doc_id:63142 │doc_id:71230 │doc_id:90123 │
└─────────────────┘       └─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┘

对 es 中的数据进行查询时,本质就是求多个排好序的序列求交集。非数值类型字段涉及到分词问题,大多数内部使用场景下,我们可以直接使用默认的 bi-gram 分词。什么是 bi-gram 分词呢:

                                                             
                             今天天气很好                          
                                                             
                                                             
+---------+ +---------+ +---------+  +---------+  +---------+
|  今天     | |  天天     | |  天气     |  |  气很     |  |  很好     |
+---------+ +---------+ +---------+  +---------+  +---------+