前言
ES 简介
Elasticsearch官网:https://www.elastic.co/cn/products/elasticsearch
ElasticSearch是一个基于Lucene语言开发的搜索web服务,对外提供了一系列的Rest风格的API接口,因此,任何语言都可以通过发送http请求来实现ElasticSearch的操作。
搜索技术
搜索技术在我们日常生活中常常用到,例如:
- 搜索综合网站:gool搜索、百度搜索
- 电商网站:京东、淘宝的商品搜索
有些搜索业务可以在数据库中完成,但是有些却不行。因此需要一种新的搜索方案去解决海量数据,复杂业务的搜索。
数据库搜索的问题
要实现类似百度的复杂搜索,或者京东的商品搜索,如果使用传统的数据库存储数据,那么会存在一系列的问题:
- 性能瓶颈:当数据量越来越大时,数据库搜索的性能会有明显下降。虽然可以通过分库分表来解决存储问题,但是性能问题并不能彻底解决,而且系统复杂度会提高、可用性下降。
- 复杂业务:百度或京东的搜索往往需要复杂的查询功能,例如:拼音搜索、错字的模糊搜索等。这些功能用数据库搜索难以实现,或者实现复杂度较高
- 并发能力:数据库是磁盘存储,虽然也有缓存方案,但是并不实用。因此数据库的读写并发能力较差,难以应对高并发场景
倒排索引
倒排索引是一种特殊的数据索引方式,虽然于数据库存储的数据结构没有太大差别,但是在检索方式上却大不一样。
基本概念
- 文档(Document):用来检索的海量数据,每条数据就是一个文档
- 词条(Term):对文档数据或用户搜索数据,利用某种算法,得到的具备含义的 词语就是词条。
例如,数据库中有下面的数据:
id | title |
---|---|
1 | java核心技术卷 |
2 | 数据结构与算法 |
那么这里的每一行数据就是一条文档 ,把标题‘数据结构与算法’分词,可以得到几个词语,如‘数据’就是一个词条。
数据搜索流程对比
常规搜索流程
假设用户要搜索"谷歌创始人跳槽",来看看倒排索引的传统查找在检索时的区别:
因为复杂搜索往往是模糊的查找,因此数据库索引基本都会实效,只能逐条数据判断。基本流程如下:
1)用户搜索数据,条件是title符合"谷歌创始人跳槽"
2)逐行获取数据,比如id为10的数据
3)判断数据中的title是否符合用户搜索条件
4)如果符合则放入结果集,不符合则丢弃。回到步骤1
如图:
如果有5条数据,则需要遍历并判断5次。如果有100万数据,则需要循环遍历和判断100万次。线性查找和判断,效率极差,一个10mb的硬盘文件,遍历一遍需要3秒。
倒排索引搜索流程
倒排索引的数据存储方式与数据库类似,但检索方式不同。
1.数据存储方式
文档列表
首先,倒排索引需要把文档数据逐个编号(从0递增),存储到文档表中,并且给每一个编号创建索引,这样根据编号检索文档的数据就会非常快。
词条列表(Term Dictionary):
然后,对文档中的数据按照算法做分词,得到一个个的词条,记录词条和词条出现的文档的编号、位置、频率信息,如图:
然后给词条创建索引,这样根据词条匹配和检索的速度就非常快。
2.检索数据过程
倒排索引的检索流程如下:
1)用户输入条件"谷歌创始人跳槽"进行搜索。
2)对用户输入内容分词,得到词条:谷歌、创始人、跳槽。
3)拿着词条到词条列表中查找,可以得到包含词条的文档编号:0、1、2、3、4。
4)拿着词条的编号到文档列表中查找具体文档。
如图:
虽然搜索会在两张表进行,但是每次都是根据索引查找,因此速度要比传统数据库搜索时的全表扫描速度要快的多。
关于倒排索引的效率:
500万条数据 词条是50万 查询时间是 2s
5000万条数据 词条可能还是50万 50万词条的检索时间就是2s
也就是说 是在有限的数据中去查找无限的数据 相对来说 数据检索的效率就会提高
Lucene
在java语言中,对倒排索引的实现最广为人知的就是lucen,目前主流的java搜索框架都是依赖Lucene来实现的。
- Lucene是一套用于全文检索和搜寻的开源程序库,由Apache软件基金会支持和提供
- Lucene提供了一个简单却强大的应用程序接口(API),能够做全文索引和搜寻,在Java开发环境里Lucene是一个成熟的免费开放源代码工具
- Lucene并不是现成的搜索引擎产品,但可以用来制作搜索引擎产品,比较知名的搜索产品有:Solr、ElasticSearch
- 官网:http://lucene.apache.org/
企业生产中一般都会使用成熟的搜索产品,例如:Solr或者Elasticsearch,不过从性能来看Elasticsearch略胜一筹。