开发者学堂课程【高校精品课-上海交通大学-企业级应用体系架构:Searching】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/75/detail/15838
Searching(三)
内容简介
一. Lucene 建立索引的方式
二. 反向索引
三. 搜索
四. 如何建索引
五. 运行
六. 四种域的区别
七. 四种域的实例
八. 如何实现更新
九. 置顶与排序问题
八.如何实现更新
它的更新是先删除再添加的,并不是在现有的上面直接更新的。所以当我们想要把城市哈姆斯特丹改成别的,就必须把当前的按照查询条件删掉 document ,然后再写入。它不是只删除一条,而是把整个 document 都删掉,所以新的 document 的其他内容,还需要再设一遍,然后添加进去 optimize,这就相当于做了一次 update 。
九.置顶与排序问题
我们看到的搜索引擎一般都会有搜索的时候应该把哪个文档置顶的问题。这取决于 boost factor,factor 这个值越高,就说明它越容易被搜索,它就越容易被置顶,置上去就更容易被搜到,排列的更靠前。那如何去设置呢?就是在真正进行 document ,在添加的时候,前面动作都是一样的,后面就要调用 setBoost 来设置值,默认值是1,设成比1大就表示它比较重要,设成比1小就表示它不太重要,这样就可以改变查询到他们之后的一个排序。
Lucene 真正在做搜索的时候,还做了一些优化,它的大量操作发生在内存里,所以当你在写入修改一个内存的时候,如果不去做 optimize 这个动作,那就很难让别人直接能看到你的 index ,需要去等,直到 Lucene 愿意去把它写出来。直接调 optimize 就相当于在告诉它,现在就把更新过的索引写入到硬盘,让别人能够看到。 Lucene 也支持多线程的操作,多线程非常重要,在很多的应用里面都在用。它也支持多个线程从不同的 document 里面去读取内容,把结果写到 RAM 里面,然后把多个 RAM 的内容在 indexwrite 里面去合并,这些内容再写入到 index 里面去。这些动作天生就是多线程的,发生在背后。
当然写入( IndexWriter )也是一样的,它也是用多线程的方式来实现的。
在进行搜索的时候,我们需要定义这个 query 。那么 query 是如何定义的, Query 是要定义一个搜索项,项就相当于 key ,当我想查 subject 等于 ant 这样的项,这个项创建了一个 term query ,然后 query 就在 IndexSearcher 上面就能去 search ,就得到了 hits ,基本上就是这样一个写法,它可以来搜索到你想要的东西。
更复杂的就是你可能要有一个不像上面这样,用一个 term 来创建的 query 。它需要去解析一下相应的查询的语句。这是 Lucene 的一个细节,即 query 不是通过查询下面生成,而是通过它指定的一个接口,一个 pass 接口输进去,如果你符合它格式要求的内容,它就去产生一个 query 。但是不管哪一种,执行完之后都是一个反 hits 类型的对象,下面的操作是一样。
最后要讲一个 Lucene 上的问题就是,Booster 是否就是决定它排序的唯一因素。实际上 Lucene 会把每一个文档都计算出一个 score ,这个 score 决定了它在文档的结果里面、在搜索的结果里面、在 hits 里面是如何排序的, booster 只是其中的因素之一。
实际上,它用到的就是我们经常提到的,一个叫做 TFIDF 的算法。TFIDF 是说文本的词频乘以逆向文本词频,作为这一个文本的重要性。词频是指在文档里出现了多少次,出现的次数越多,这个词越重要,但是还有一种情况,比如“我”“的”这种词也在很多文档里出现,文本的词频非常高,但是这样的词并不重要,而且实际上我们在搜索这样的词的时候,通常将它们过滤掉。 TF 是说,我在指定的这些文档里,某个词出现的频率。 IDF 是说,文档总数用 D 的质来表示,这个词再除以出现在哪些文档里。比如,“第”这个词,先取它出现在哪些文档里的数量,然后要做一系列包括取对数的操作。这说明如果一个词例如“我”“的”,它们太常见了,在大量的文档里都出现,所以这个值除出来就接近于1,取 log 后接近于0。
如果这个词只在少量的文档里出现,比如,这里面是所有动画片的一个脚本, Tom 只在猫和老鼠里出现了,其它的都没有出现,上面的值除以下面的值,得到一个远远大于1的值,取 log 后就比较大。像“我”和“的”在所有文档里都出现,这一项基本上约等于零,所以即使它的词频很大,乘以 IDF 之后就会变得很小。也就是说,这个词如果是一个通用词,在大量文档里出现,它就没有搜索价值,只有在少量文档里出现的词,才有搜索价值。
这个算法前一部分就是我们设定的 TFIDF 的值,中间一部分就是boost 的值,它可以设成1.5也可以设成0.1,再往下就是它的正则化以后的值,这个值给出了在这个域里面某个项出现的数量。那为什么要做正则化呢?
有些项可能出现的非常多,有些出现的非常少,如果直接拿频率去做,就会非常复杂,这个值乘出来可能差异非常大,所以做正则化就是为了把这个值压到0到1的范围里面去做。这样,整个处理完后出来的 score 才是整个文档在查询结果里面排序的依据,而这里面最重要的是 TFIDF ,后面两个是可以自己设置的。前面的部分就是我们说的自然源处理里面做搜索结果排序的一个基本依据。当然 TFIDF 是其中之一,还有另外的因素比如链接数,像 Google 这样的搜索引擎要考虑链接数等。后面是我们在拿 Lucene 讲全文搜索的原理。
全文搜索的基本上都是这个逻辑,但是反向索引的结构可能有差异。因为,如果不建这种反向索引,首先用关系性数据库就很难操作,正向索引很难操作。
如果做正向的索引,你仍然避免不了全表或者全库的扫描这个动作,只有建反向索引才能按关键词搜索,这样才会比较快。运行 Lucene 比较简单,不需要依赖其他任何东西。而 Soft 需要安装工具后再运行。