mysql数据库最左前缀匹配原则的温习:
联合索引(product_code,pkg_code,name) ,B+树是按照从左到右的顺序来建立搜索树的。如('123456789','12345','xxx')来检索数据的时候,B+树会优先匹配product_code来确定搜索方向,product_code匹配成功再依次匹配pkg_code、name。
但是如果拿 (‘12345’,'xxx')来检索时,B+树没有拿到一级索引,根本就无法确定下一步的搜索方向。('123456789,'xxx')这种场景也是一样,当product_code匹配成功后,没有pkg_code这个二级索引,只能在product_code相同的情况下,去遍历所有的name。
like '%xxx%'不会使用索引,而like ‘xxx%’可以使用索引。
接下来考虑这样一个场景:用户在搜索框输入xxx,希望自动提示包含xxx字样的提示词。在数据库中搜索包含“xxx”字样的数据,那么就注定要使用select product_code, pkg_code, name from items where product_code='12345678' and pkg_code='12345' and name like '%xxx%';
这里一级索引和二级索引还是生效的,但是接下来的模糊搜索就要扫描所有的product_code='12345678' and pkg_code='12345' 的数据了,即便是给name建了索引也用不上。
索引的核心是排序,而大部分的搜索(数据库)引擎都是用B+树结构来维护索引,索引的更新会导致大量的IO操作,同时对整个B+树结构进行调整,我们需要寻求一种高效的索引方式。
Lucene就可以用于解决这种问题。它解决问题的方式是在扩展索引的时候不断创建新的索引文件,然后定期的把这些新的小索引文件合并到原先的大索引中,这样在不影响检索的效率的前提下。
首先从原文提取分词,排序顺序存储的同时,有另外一个排好序的关键词列表,首先是要分词:北京年度版宠物狗一年期,就会把它分为北京、年度版、宠物狗、一年期等词汇。
然后开始建立索引文件,建立索引文件的过程,实际就是把documents文件一个个加入索引中,Lucene的做法是最开始为每个新加入的document独立生成一个segment,放在内存中。而后,当内存中segments数量到达一个阙值时,合并这些segments,新生成一个segment加入文件系统的segments列表中。
每个索引文件都是一个完整的segments索引文件,在搜索时,Lucene会遍历这些segments,以segments为基本单位独立搜索每个segments文件,而后再把搜索结果合并。
将源中需要的信息加入Document的各个Field中,并把需要索引的Field索引起来,把需要存储的Field存储起来。
用户提供搜索关键词,经过analyzer处理。对处理后的关键词搜索索引找出对应的Document。用户根据需要从找到的Document中提取需要的Field。
两个文档, doc1和doc2他们的内容分别如下:
Doc1: 北京年度版宠物狗一年期
Doc2: 广州年度版二手车半年期
如果按照正常的索引建立如下所示:
文档名 关键字 次数
Doc1 北京 1
Doc1 年度版 1
Doc2 广州 1
Doc2 年度版 1
……
这里索引的建立是以文档为标准的, 即“document包含哪些单词”。
这样当文档很多的时候数据量将非常的大, 检索效率会明显下降的。
倒排索引是以单词为标准来进行索引的建立的,即“哪个document包含单词x”。还以上面的doc1和doc2为例:
关键字 出现的文档 次数
北京 doc1 1
广州 doc2 1
年度版 doc1 1
doc2 1
……
这样当你想要查询年度版的时候就只搜索doc1和doc2,而当你想要搜广州的时候就只需搜索doc2。减少了文档搜索的数量。
下篇文章会结合代码和一个例子来解释索引。