开发者学堂课程【高校精品课-上海交通大学-企业级应用体系架构:Searching】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/75/detail/15838
Searching(二)
内容简介
一. Lucene 建立索引的方式
二. 反向索引
三. 搜索
四. 如何建索引
五. 运行
六. 四种域的区别
七. 四种域的实例
八. 如何实现更新
九. 置顶与排序问题
六.四种域的区别
1.Keywords
那这四种域有什么区别呢?第一个 keywords ,它本身不会去被分析,也就是说它不存在主动抽取里面的词,比如 contents 来了,必须要把里面的词抽取出来,例如去掉标点符号,然后做一些词性的转换,再例如复数、单数要识别成一个词等, Lucene 说 keywords 你就不用处理了、不用去做这个,但是 keywords 在索引里面是被索引并且被存储的,也就是它会出现在那个索引里面。比如我们写的文件名就是一个 keywords ,我们当然希望文件名是被索引的,而且它在索引里面会被存储的。这样我将来在搜索的时候直接去搜索索引,就能拿到文件,不需要到原始的文件存储的地方去找它的名字。这一类是关键词直接参与索引、被存储被拿出,而且比较简单,不需要再对它做额外的处理。
2.Text
我们把 content 即内容放在里面,它肯定是要被处理的,因为它是完整的一篇内容。它的内容要抽取出来,然后参与,即对它 ( content )在进行索引。比如一篇文章的摘要用这种方式放进去,未来,别人在读取这篇摘要的时候,它就像论文的关键词在简要描述这篇论文是做什么的,所以他要参与这个索引,这样别人在搜索时就能搜到,例如要论文是关于新冠病毒的,只要搜索新冠病毒,就可以马上搜到它出现在你的摘要里。但是因为它要被搜索,被存储在这个索引里面,所以摘要不能过长。如果过长,索引会变的非常大。
3.UnIndexed
内容或者域如果是 unIndexed ,既不用去分析,也不用去索引,但是它的值要存在索引。比如这个内容是作者简介或者作者的一些联系信息这样的东西,找到了这个文件、找到了它的索引进而找到了这个摘要,只需要知道这个论文是做什么的就行了,当然这个内容在被拿出来的时候,最好能把这个作者信息一起带出来,但是不需要对作者信息去做任何的额外的处理,整个塞进去就可以了,而且它也不参与索引。因为当不知道论文内容的时候,就去对所有的作者做个排序或者去检索它是没有任何意义的,所以就是用的这种方式。
4.UnStored
它会被分析、被索引,但不会存储到索引。这就相当于论文的正文本身,因为内容太多,所以只告诉你这个论文里面包含这个主题,当你去查正文的时候,正文里的内容参与索引后要扔掉,比如它包含了一些关键词例如新冠病毒,我想要知道新冠病毒在这个文件的第几行出现过,所以只需要储存它在这个文件的第几行,在这个文件里出现了几次,至于这个论文本身完整的内容就不需要储存在索引里,目的就是保持索引的大小,不能太大。
七.四种域的实例
所以在一个 document 里面就会包含四种不同类型的 fields ,将一个文件的内容拿出来之后,应该使用哪一种?这完全取决于前面。举个例子,这里有国家的 ID ,荷兰和意大利,还有两句描述,汉姆斯特丹有很多桥,威尼斯有很多船,然后这两个城市是汉姆斯特丹和威尼斯,在建索引的时候,国家 ID 要包含在索引里,但是国家的 ID 本身不参与检索,因为它对检索是没有任何帮助的。然后国家,即这里的荷兰和意大利,用的是 UnStored 。如果脱离了阿姆斯特丹,或者是威尼斯这样的城市,单独去检索荷兰和意大利是没有任何意义的,但是当检索到一个城市,它是荷兰或者阿姆斯特丹或者威尼斯时,希望能把国家的名字带出来,所以国家要存储在索引里,但是它本身不用去进行分析、检索,城市是必须参与这个检索,并且存储在里面,将来就需要用它来进行搜索。当问到桥或者是舟出现在哪些文档里,那么阿姆斯特丹有很多桥和威尼斯有很多船、独木舟这样的内容本身就需要参与索引。但是这种参与完索引之后,由于这两个内容比较长,不要存储,所以实际上只存储了这些词在哪个文档里出现了、出现了几次、在什么位置,但整个文档内容本身并没有存储。这两句比较长的描述,就可以称为 UnStored 。
即使是做全文搜索, Lucene 在这建的是反向索引,客户在把一个 document 放进去之后,还是可以有自己的一些设置,也可以来控制这个索引的样子。这四个域就是在告诉我们,它到底要存哪些东西,它是按什么东西在进行索引,索引里面包含哪些内容。如果我们的 document 里面包含的域不同可以吗,能不能把这种 document 放到一起建一个索引,这些是允许的。也就是说,在 Lucene 里面它比较宽松,如果一个 document 里就包含所有 document 里面包含的域,比如有一个 document 包含了 name 和 price ,另外一个里面包含的是 name、age、 和 gender ,后面两个如果按 name 去做索引, Lucene 允许把它索引到一起。也就是说,上面是商品下面是人,商品和人可以放到一起,按照名字去检索,比如既可以找到叫汤姆的人也可以找到叫汤姆的商品,例如一个玩具。这个 document 里面包含了不同的域,对于这些不同的域,实际上就像在定义 key value 一样,这个 key 先定义好,比如它有一个 text 类型,即既要参与检索,也要参与分析,还要进行存储,这样的域叫 word ,这个 word 先被定义好了一个词,就是 fast ,那么我未来能否在这个域里追加其他词。也就是说,这个 key 仍然是 word ,但它的值是由一组词构成,就像 Jason 里面我们的 key value , value 是一个数组,不是一个单一的词,但它是允许的。
继续做 add,由于 add 的 key 跟之前的是一样的,它就把 word 的 key 对应的值变成了一个数组。我们将像quick、 rapid、 speed 这样的一些 fast 的同义词放了进去,现在我们的 word 里,实际上就包含了四个词,所以在进行搜索、查询的时候,如果是在搜索 word 的这个域,就可以指定这四个词,它里面的 document 就包含了这四个词,只要搜索这四个词当中的某一个,那么这个 document 就会出现,例如查询 quick ,这个 document 里面既有这四个词, word 中也有这四个字,而且包含了 quick ,这个document就会被查询出来。
我们建立了一个索引,这个索引在读出来之要 ID 为1的这个元素删掉。删掉之后,按道理,我们把 reader 关掉,再重新打开去读里面内容时,会发现它原来里面有两个文档,最大的文档 ID 为2,并且有两个文档。当把1删掉后,最大的那个文档,它的 ID 是2。但是现在里面只有一个文档,相当于 ID 等于1的东西丢了,而且,可能以后就再也无法找到。如何把这个1充分地利用起来呢?在删除这个1的同时,要把这个关掉,然后要用 writer 对它 optimize一下。 Optimize 这个动作做完之后,再去打开一个处理过之后的索引,然后我们再去读的时候,就会发现,现在里面 ID 最大的那个是1,并且里面也只有1,也就是说 optimize 这个方法会把索引重新做一次,即所谓的优化,它会去防止 ID 等于1的删掉之后,里面的这个 ID 唯一的 document 就成为了一个洞,以后再也没有用到。也就是说, ID 会不断的增加,这个地方会把它整理的。当然,忽略掉这点也是可以的。但是这个动作比较好,相当于它保证你的 ID 总是从1开始到一个最大值之间是紧凑排列的,不存在洞。而后面的就像我们在使用关系数据库一样,如果没有这个动作,就会导致前面删掉之后,它就变成从2到 max ,下一个就继续从 max +1开始,前面的1就永远地没有了。所以在删除的时候,最好 optimize 一下,然后按 undeleteAll 方法可以把所有的删除掉的 document 都恢复出来。实际上,打标记把所有删除的 document 写到这样的文件里,按 deleteAll 的时候就会把这些文件恢复出来。