Searching(一)|学习笔记

简介: 快速学习 Searching(一)

开发者学堂课程【高校精品课-上海交通大学-企业级应用体系架构:Searching】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/75/detail/15838


Searching(一)

 

内容简介

一. Lucene 建立索引的方式

二. 反向索引

三. 搜索

四. 如何建索引

五. 运行

六. 四种域的区别

七. 四种域的实例

八. 如何实现更新

九. 置顶与排序问题

 

一.Lucene 建立索引的方式

image.png

我们来讲解一下 Lucene 建立索引的方式是什么

按顺序扫描每个文件这种方法由于缺陷很大而且非常耗时间所以 Lucene 为了使搜索速度变快,先把这些文本做一个索引,不需要去做全文扫描

image.png

Lucene 将索引建成如图所示的样子,当客户抽取了这个文档里的内容之后,客户诉 Lucene 在这里面我需要设置一些什么样的域,这些域就会去建立一个索引, Lucene 再统计每一个域里不同的值,比如在记录 author 这个域时,我这一堆的文档里面就出现有 author 这样的一个表述,它里面就会有我定义好什么样的人,有两个不同的人,他们各在一个文档里出现过, author 它有两个不同的取值,各一个文档里出现过,那这个文档是谁紧跟着

比如说这里如图,叫做 contents 的里面有一个叫 junk 的东西出现过两次,那它在下面的表格里就会告诉你上面 action 出现过三次,它也会在下面的表格里告诉你 unie 出现在两个文档里,然后会在下面的表格里告诉你是哪两个文档即56文档,然后在这两个文档里各出现过一次和两次那这里一次和两次分别是指,1次是在这个文档5里的第9位置2次是在这个文档6里的位置1和位置3。这个索引的意思就是,如果未来我要找一个 offer 的名字那通过这个索引就能看到,它出现过一次,然后到下面的表里看它在哪个文档里出现过,再找它出现的位置,以及在这个文档里出现了几次,根据它的位置,就能找到它在哪儿,这就它的索引当然这是一个概念,它里面比这个稍微复杂一点

 

二.反向索引

它为什么叫反向索引跟反向索引对应的自然是正向索引我们见到的索引的一般概念可能会说一个文档里它包含了哪些词,比如词1出现了两次2出现了三次等,然后还有一个表记录都有哪些文档,比如有文档一、文档二,文档一包含哪些词

这是我们想要一个正向索引正向索引为什么用于查找都比较慢,比如用户想找包含 Tom 的这种人有多少,那就必须先去找有多少文件,在每个文件里面去找 Tom 这个词有没有被统计到,如果有他出现了多少次,然后把这些次数全部加起来,才能知道 Tom 在当前的这一组文件里出现了多少次,效率很低如果反过来写,把所有的文档里内容拿出来,比如 Tom 出现了,出现在十个文档里,这十个文档分别是哪些文档在每一个文档里它都出现了几次,每一次出现在这个文档里第几个词。是和正向索引反过来,所以所谓的反向索引就是在正向索引的方向相反,它不是按照文档这种结构去索引,是反过来拿词里面出现的内容索引指向出现在哪一些文档的什么位置上但是建好这种索引之后,它就适合于我们做全文搜索,你确实就是在整个这一个目里所有的文件里去找这一个词出现在哪里,这就是 Lucene 建立这个反向索引的原因。那么,反向索引就意味着它和正向索引不同,几乎所有的全文搜索的引擎都是用反向索引这种方式建索引但是有的任何索引,一样能实现这个功能,比如关系性数据库没有索引能实现直接扫描就可以。建立反向索引的目的就是要让客户在对数据进行操作的时候,速度正是因为它建立这样的反向索引,所以客户在里面按内容搜索的时候,比如要搜某个词出现多次的时候,它就会比较快这是概念上的一个解释,实际上比这个要复杂,所以我们后面要稍微展开去讲它这个复杂程度指的是什么

 

三.搜索

image.png

我们现在可以看到,有了这样的索引,现在搜索就可以只在刚才的这个索引去找这些词,它就会告诉你这些词出现在哪一些文档里面,它出现的位置什么。

如此,通过反向索引就可以使搜索的速度变快,总的来说,它就在加快速度但是在加快的时候到底能快到什么程度,不是有一个索引就能完善的,还与文件数量有关,文件数量多到一定程度可能会影响搜索速度当然相对于全文扫描要快的多,还有就是与搜索内容有关,现在是找一个词会比较简单条件比较复杂时比如 TomJerry 同时出现,或者出现 Tom ,但是没有 Jerry 一起出现的概率是多少,就是类似这种复杂的查询短语的查询、通配符查询它是不是都支持

那我们找一个例子,就是在讲 Lucene 的时候,既然要去做全部搜索它包含两个部分,一个是做索引,一个是做搜索,那么这两件事分别是怎么做的为了去讲清楚这件事情,这个例子没有直接说对一个文件操作,而是对一个目录里所有文件进行操作,这样去做这事情

 image.png

那我们来看一下,先讲一下例子,然后讲解代码先建索引而且导入Lucene 的包,然后在执行时用命令行传递两个参数,一个是建好索引后放在哪里,第二个是对哪个目录里所有的文件进行操作。它里面核心的函数是这个 index(indexDir,dataDir),就是我们要去建索引,前后只是记录一下索引用了多少时间

 

四.如何建索引

image.png

1.前期准备

先检查一下要处理的目录和建好的索引在不在,建好索引要注意,前面目录(第二张图片),它不是一个文件而是若干个文件,要放到一个目录里,所以建好的索引要放到一个目录里面然后建索引针对的那些文件在一个目录,两个目录先做了一下防御性的编程,就是在看这两个目录本身是否存在,接着 Lucene 的代码,红颜色是跟 Lucene 相关的代码 Lucene index writer 这个对象向里面写东西。

image.png

2.Analyzer 和 optimize

实际上写的内容进来之后需要做解析解析后需要通过分析器去分析,把里面关键词抽出来,然后去记住这个词在哪些位置出现在哪些文章里出现等等,主要是靠分析器来做处理,然后写入索引的目录里写成几个文件

所以在建立索引的时候,除了要用一个 writer 索引写进去要有一个 Analyzer 。因为在这个例子里面,我们放入的是常规的内容,所以用的是 Standard Analyzer ,如果有一些特殊的需求,可以自己实现一个 Analyzer在这个例子中我们用标准  Analyzer 来做分析产生索引,然后我们在这里面写了一个关键的建立索引的内容,那么这个过程就在建立索引建立好索引之后,在这个 writer 里面把文档的数量写进去,然后一定要调一下optimize ,optimize 它才真正把这个内容写入到文件,并且把它写到硬盘上去,这时候这个才能用索引。否则,如果没有 optimize 那么索引可能只在内存里,其他用户是看不到

 image.png

建索引过程用的是递归的过程,就是要取里面的每一个文件,对每一个文件操作,所以先去检查一下,我先把这个目录里所有的子目录和文件全部装载到 files 数组里,然后遍历这个数组看它是不是一个子目录,如果是子目录继续递归调用,如果不是子目录已经是个具体文件了,那就用 indexFile 这个函数传递进来 writer 去把 file 处理一下

 image.png

3.indexFile 如何实现的

后面我们这里写的这个函数,这里面红颜色的是跟 Lucene 相关的东西,前面是他一些防御性编程,要建立一个 document ,在 Lucene 看来,数据进来之后全部都是一个一个 document 只需要对这些 document 做索引,因此要将它组装成 document进来一个只要是单个文件就让它处理,那么进来一个文件, Lucene 就建立一个新的  document ,把这个文件里面的内容用 FileReader 读出来,读出来以后要塞到这个 document 里面去,这个 document像一个二维表,也有很多的字段,或者说,可以认为它像个 Json 一样有很多的域,其中有一个叫 text text的意思是 text 这个域里的内容,将来在建索引时候就是建立索引的依据,并且它要直接存在索引我们把内容写到这个 text 里面,这个里面本身也可以是一若干个不同的属性,我们现在给它定义一个属性叫 contents 就是说,它有 text 类型或者其他类型, text 里面又分为各种类型比如 contents ,但是这个 contents 是我们自己自定义的也就是说,在 document 里增加了一个 text 类型的名字叫 contents 的一个属性,它的值可以从文件里读出来然后在这个 document 里面增加了一个叫做 keyword 类型的 document keyword 也会被建立索引,也会被写入到索引里面去,但是他本身不参与这个索引可以理解为在这个里面还有叫 keyword 类型的属性我们对它起的名字叫做 filename ,就是把这个 f 去掉它带路径的那个名字之后,剩下的这部分写进去,前面就是在组装这个 document 。

现在我们是把要建立索引的那个文件里的内容拿出来到了 document 里面,把文件名放到里,但是它们两个的域的类型不一样然后我们writer writer 索引里面写东西,告诉 Lucene 现在多了一个  document现在创建的这个document ,你 at 进去

 image.png

4.递归调用的过程

这样的话,我们可以看到这个递归调用的过程如果是子目录一级一级往下,如果是文件,它直接写就是说这个 writer 里面,未来就添加了一系列的 document ,这个方法执行完之后到这里 writer.optimize,write 只是往里面添加了一系列的  document 如果不做 optimize ,索引就无法生成,所以一定要调一下 optimize ,索引生成之后把它关闭掉,这个索引就能被其他人使用,这是索引的过程

 

五.运行

 image.png

运行一下刚才这个代码然后传递给 Lucene 这个目录,比如指定一个目录去跑,就会告诉你已经把这里面所有内容全跑一遍这个目录里可以带子目录,就把这目录里所有的内容全部读出来去建立一个反向索引

 image.png

反向索引建好客户就可以去搜索如何去搜索呢?客户一个参数,要搜什么索引在哪里,前面是一样做一个防范性编程,然后它就开始搜索,搜索的时候就在指定的索引目录里去搜

 image.png

搜的时候,首先要打开这个索引 searcher,然后创建一个搜索的字符串,这个字符串即包含要搜什么、要在哪里搜刚才在这里添加了一个名为 contents 的域,所以说清楚在哪里去搜contents 就将两个关联起来其次按照什么样的 Analyzer 去搜,因为我们建索引的时候用的就是 StandardAnalyzer ,所以在这里搜的时候仍然用了,这样做完之后,我们就 searcher  对象上面去执行 query ,那它就会找到满足这个 query 的结果,这些结果就放到了一个叫 hits 的对象,hits 对象实际上是个数组,所以我们可以遍历它。它里面就放进去了所有满足这个查询条件,就是 contents 里面包含了满足查询条件 documents ,所以在里面去遍历的时候就可以取出一个一个的 documents ,那去把 documents 里面 Filename ,即 keywords 里面的 filename 这一个值取出来,那它就可以输出所包含了要去查找的文件的这个文件名它就会产生这样的结果

 image.png

image.png

在这里举一个例子,给大家演示一下 soft 。这是 Lucene 的例子,那这个例子和你们现在看到的稍微有点差异的是我稍微改了一点,因为目录的问题稍微改了一点,就是这里建了一个resource目录,里面两个 Lucene 的文件,这两个文件是啥呢,就是 Lucene 的 license 文件,和一个说明文件。在这边 index file 文件的时候,我会让去处理这个 resource 目录里的东西,其他的跟刚才写的差不多

 image.png

它在执行的时候就会去建这个索引,这时我指定让去建 resources 目录里的东西, resources 目录里就会有一个隐藏文件,有两个是我刚才放进的 Lucene1 Lucene2 。这个索引建完之后,我们就可以进行搜索,搜索代码跟前面基本上一为了在上面能够自己搜输入,我稍微做了一下调整,比如我们去搜Apache 就会搜到在 Lucene1 Lucene2 中都有,我可以看一下 Lucene1 Apache 在这里面位置,反正他要在这儿有一个 Apache,他就会说在这两个文件里面都出现了 Apache ,它方式就这样对于 Lucene 的运方式,它不需要自己去取一个所谓的 Lucene 服务器,它没这个概念,你只要在你的包里面打进去 Lucene 相应的包就可以

 image.png

这里面我们看到的有一个 Lucene  call ,如果你用pop 文件来做这个,用 main 来开发的话,就要把它打进 Lucene 。这个 index 就是它刚才跑完之后产生的索引,我们让它把索引写到了如图所示的位置, index 实际上写了好几个文件,共同构成

index 文件

image.png

打开一个就能看到它生成的格式它的格式是什么东西我们不知道,反正就是按照它自己的格式去写进去

image.png

如图所示为它生成 index ,我们通过 Lucene 知道了大概的过程,即它如何生成反向索引的、如何代码的。但实际上,如果大家上 Lucene 的网站会发现和 Lucene 的网站并列的 Soft 这个工具是在 Lucene 的基础上做了一次封装产生,就是为了让它更好用,因此 Lucene 本身的原生的 Lucene 的编码,我们就不需要详细探讨。然后我们来看 Lucene 里面的原理,因为 so 其实是在 Lucene 的基础上开发出来的。在进行操作的时候,在里面写的东西 keywords 、 text ,其实它还有两种东西, unindexed  unstored ,就是往 Lucene  document 里面去写 field 域的时候,它有四种不同类型的域就是在这边我们看到有 keywords、unindexed、unstored、text ,这个document 里面有四种不同的域,刚才我们是遇到了 text  index 这四种不同的域添加到 writer 里面,去做索引的时候,它处理方式是不一样的。

相关文章
|
存储 安全 文件存储
Searching(二)|学习笔记
快速学习 Searching(二)
243 0
Searching(二)|学习笔记
|
算法 搜索推荐 数据库
Searching(三)|学习笔记
快速学习 Searching(三)
213 0
Searching(三)|学习笔记
|
存储 算法 NoSQL
Caching(二)|学习笔记
快速学习 Caching(二)
123 0
Caching(二)|学习笔记
|
存储 缓存 JSON
Caching(三)|学习笔记
快速学习 Caching(三)
157 0
Caching(三)|学习笔记
|
存储 缓存 NoSQL
Caching(一)|学习笔记
快速学习 Caching(一)
143 0
Caching(一)|学习笔记
|
存储 缓存 负载均衡
Clustering(二)|学习笔记
快速学习 Clustering(二)
137 0
Clustering(二)|学习笔记
|
安全 Java 应用服务中间件
Distributed Object 2(三)|学习笔记
快速学习 Distributed Object 2(三)
132 0
Distributed Object 2(三)|学习笔记
|
存储 缓存 负载均衡
Clustering(一)|学习笔记
快速学习 Clustering(一)
106 0
Clustering(一)|学习笔记
|
Oracle Java 关系型数据库
Distributed Object 2(一)|学习笔记
快速学习 Distributed Object 2(一)
Distributed Object 2(一)|学习笔记
|
Java 开发者 Spring
Arch. Components 2(二)|学习笔记
快速学习 Arch. Components 2(二)
Arch. Components 2(二)|学习笔记