ImageVerifierCode 换一换
格式:DOCX , 页数:11 ,大小:24.75KB ,
资源ID:20927158      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/20927158.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(lucene搜索实现过程详解Word格式文档下载.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

lucene搜索实现过程详解Word格式文档下载.docx

1、7 生成Query子对象。Query query = parser.Parse(strQuery);其中,strQuery为用户输入的待查询的字符串。该句的主要功能是将用户输入的字符串进行分词,并记录每个Token之间的位置关系,以便于后面的查询。当然,Lucene允许用户直接创建Query,也允许用户采用多种方法构建Query。例如:按词条搜索TermQuery、“与或”搜索BooleanQuery、在某一范围内搜索RangeQuery、使用前缀搜索PrefixQuery、多关键字的搜索PhraseQuery、使用短语缀搜索PhrasePrefixQuery、相近词语的搜索FuzzyQuer

2、y、使用通配符搜索WildcardQuery。各种方法原理相同,都是将各单个Query搜索,然后再将各自结果按照“与”或者“或”的关系得出最终结果。在本文中,我们将以代码所示的简单方式为例。8 搜索,返回处理结果。Hits hits = searcher.Search(query);在该句中,不仅涉及搜索的过程,而且还有排序、过滤等过程。7根据搜索生成的内部编号,返回真正的结果。Document doc = hits.Doc(i);三 搜索过程详解。1IndexReader reader = IndexReader.Open(该句调用IndexReader的Open方法: public sta

3、tic IndexReader Open(System.String path) return Open(FSDirectory.GetDirectory(path, false), true); 11 FSDirectory.GetDirectory(path,false),该方法获取索引文件夹的完全路径和创建临时文件路径。其中,path为索引文件所在文件夹的名称,false表示不要创建新的文件夹。该方法调用FSDirectory的GetDirectory方法: public static FSDirectory GetDirectory(System.String path, bool c

4、reate) return GetDirectory(new , create);111 GetDirectory(new , create);该方法是获取文夹完整路径的核心方法,其他方法都调用此方法。首先,通过语句file = new ;获得索引文件所在文件夹的完整路径到file。其次,根据file创建临时文件将要存放的路径:FSDirectory dir;dir = (FSDirectory) DIRECTORIESfile;dir = (FSDirectory) ;然后,进行初始化工作:dir.Init(file, create);由于现在是搜索过程,并非创建索引的过程,初始化工作只是将

5、两个完整路径传给dir。最后,返回dir。12 Open(FSDirectory.GetDirectory(path, false), true);该方法调用IndexReader的Open(Directory directory, bool closeDirectory)方法。其中,directroy就是上面返回的dir。在该方法中,有三个主要方法MakeLock、AnonymousClassWith、Run()。121 directory.MakeLock(IndexWriter.COMMIT_LOCK_NAME);其中COMMIT_LOCK_NAME为锁文件名,在Lucene中为comm

6、it.lock。此刻该文件表示有进程在读“segment”文件和打开某些段的文件。在该方法中,首先获取索引文件目录的前缀,并以此来命名锁文件名称;然后将临时文件夹的完整路径和锁文件名称组成完整了锁文件名称LockFile;最后初始化该锁:AnonymousClassLock(lockFile, this);其中this为当前索引文件目录路径。122 AnonymousClassWith(directory, closeDirectory, directory.MakeLock(IndexWriter.COMMIT_LOCK_NAME), IndexWriter.COMMIT_LOCK_TIME

7、OUT);该方法主要做一些初始化工作。其中,COMMIT_LOCK_NAME为获取锁文件的限定时间,Lucene默认时间为10000毫秒。123 Run()这是读取索引文件的核心方法。该方法代码如下: public virtual System.Object Run() bool locked = false; try locked = lock_Renamed.Obtain(lockWaitTimeout); return DoBody(); finally if (locked) lock_Renamed.Release(); 1231 根据限定时间lockWaitTimeOut获取锁文件

8、。在获取过程中,每秒钟试一次,直到获得锁文件为止。如果重试超过十次,则被阻塞。1232 DoBody();该方法首先声明一个SegmentInfos对象,用以管理SegmentInfo:SegmentInfos infos = new SegmentInfos();12321 infos.Read(directory);其中directory为索引文件目录。该方法读取Segments文件信息。1)IndexInput input = directory.OpenInput(IndexFileNames.SEGMENTS);创建一个Segments文件的输入流,用以读取Segments文件信息。

9、2)int format = input.ReadInt();读取索引文件格式信息。Lucene2.0默认为1。3)version = input.ReadLong();读取版本信息。4)counter = input.ReadInt();读取counter,counter用于给新生成的索引起名字。5)在for循环中,int i = input.ReadInt();读取segment的个数count。6)SegmentInfo si = new SegmentInfo(input.ReadString(), input.ReadInt(), directory);依次读入每个segment的名

10、字和包含文档的个数,并用Add(si);将每个si加入到ArrayList。当然,在旧版本的lucene当中,可能读取的顺序不太一样,但道理是一样的,都是根据索引的结构依次读出。12322 对于生成的索引,segment的个数可能不止一个,本文就以一个segment为例,多个segment与之类似。return SegmentReader.Get(infos, infos.Info(0), closeDirectory);读取其他文件或为其他文件创建输入流,以供以后读取。Get方法层层调用,现在只分析最后的核心方法:1)instance = (SegmentReader) ;创建Segment

11、Reader实例instance。2)instance.Init(dir, sis, closeDir, ownDir);初始化工作。3)instance.Initialize(si);读取的核心部分。首先要根据.cfs文件是否存在来判断是否是复合索引结构,本文采用非复合索引结构来说明,复合索引结构与之类似。a)fieldInfos = new FieldInfos(cfsDir, segment + .fnm读取.fnm文件信息。该方法实现如下: IndexInput input = d.OpenInput(name);name为.fnm文件名。为.fnm文件创建输入流input,以供读取。

12、Read(input);读取信息: int size = input.ReadVInt();读取字段(filed)的个数。 System.String name = String.Intern(input.ReadString();读取各个字段的名称。 byte bits = input.ReadByte();读取标志位。 下面五句是根据bits的值来判断该域是否被索引等信息。 AddInternal(name, isIndexed, storeTermVector, storePositionsWithTermVector, storeOffsetWithTermVector, omitNo

13、rms);将该域的这些信息存储,存储的方法有两种,一种是byName,根据名字来存储;一种是byNumber,根据编号来存储。Input.Close();关闭.fnm文件的输入流。b)fieldsReader = new FieldsReader(cfsDir, segment, fieldInfos);为.fdt和.fdx文件创建输入流fieldStream、indexStream,并记录document的数量size。c)tis = new TermInfosReader(cfsDir, segment, fieldInfos);读取.tis和.tii文件的相关信息,实现如下:origEn

14、um = new SegmentTermEnum(directory.OpenInput(segment + .tis), fieldInfos, false);读取.tis文件信息: directory.OpenInput(segment + );创建.tis文件的输入流。 int firstInt = input.ReadInt();获取版本号。Lucene2.0当中为2。 size = input.ReadLong();读取term的个数。 indexInterval = input.ReadInt();读取索引间隔,默认值为128。 skipInterval = input.ReadI

15、nt();读取跳跃间隔,默认值为16。indexEnum = new SegmentTermEnum(directory.OpenInput(segment + .tii), fieldInfos, true);读取.tis文件信息。由于.tis文件结构与.tii文件结构相似,这里就不详细展开叙述。d)if (HasDeletions(si)deletedDocs = new BitVector(Directory(), segment + .del如果之前有删除文档的记录,那么这里将删除。关于document的删除工作,将有专题讲述,这里就不再叙述。e)freqStream = cfsDir

16、.OpenInput(segment + .frq创建.frq文件的输入流frqStream。f)proxStream = cfsDir.OpenInput(segment + .prx创建.prx文件的输入流proxStream。g)OpenNorms(cfsDir);读取.f文件的相关信息。4)return instance;返回该实例。该实例记载了各个文件的信息。也就是说,关于索引各个文件的信息,记录在searcher当中,后面的查询工作将用到searcher。关于searcher的结构,请参看Lucene的源代码。2IndexSearcher searcher = new IndexS

17、earcher(reader);该方法主要是进行一些初始化工作。需要说明的是similarity,它是用于后面排序的积分计算的。这里调用similarity = Similarity.GetDefault();即采用Lucene默认的值。3QueryParser parser = new QueryParser(describ, analyzer);声明一个查询分析器,并进行一些初始化的处理。该方法调用CharStream类型为参数的重载构造函数public QueryParser(CharStream stream);然后初始化。31 public QueryParser(CharStrea

18、m stream);该方法主要是利用一个空的CharStream类型来进行初始化工作,为下面的分词工作做好准备。初始化过程中,涉及很多参数,比如:fuzzyMinSim最小相似度,fuzzyPrefixLength前缀长度,用于模糊查询;一些以jj开头的参数,是由javaCC生成的,用于分词的工作,这点在分析器的文档中将详细介绍,这里不再累赘。32 将传入的分析器analyzer、字段field传给对象:analyzer = a;ield = f; 至此,完成查询分析器的初始化工作。4Query query = parser.Parse(strQuery);这是对用户输入字符串处理分词和记录位

19、置关系的最核心部分。在该方法中,主要只有两句。41 ReInit(new FastCharStream(new ;411该方法首先用StringReader对象构造一个FastCharStream对象作为重新初始化(因为在声明QueryPaser对象的时候已经初始化过)的参数。即:new FastCharStream(new ;412 调用QueryPaser的方法ReInit(CharStream stream);其中stream就是上面生成的FastCharStream对象,FastCharStream类是CharStream类的子类。该方法和声明查询分析器时的构造方法相似,这里就不再说明

20、。42 return Query(field);其中field为要查询的字段名。该方法比较复杂,但我们只要把握一点,就是它的主要功能是对用户输入内容进行分词,然后构建Query对象用于查询,也就很好理解了。421 mods = Modifiers();该方法主要是判断用户是否使用复合查询,即是否使用BooleanQuery等查询。本文为了简单起见,就以简单查询为例,复合查询的方法是类似的,这点我们在前面已经讲过了。4211 Jj_ntk();这个是javaCC生成的方法,用于判断得出mods的值。mods的默认值是0,即简单查询。return (jj_ntk = (token.next = t

21、oken_source.GetNextToken().kind); 或者return (jj_ntk = jj_nt.kind);由此可知,该方法返回的是字符串的类型。4212 switch (jj_ntk = - 1) ? Jj_ntk() : jj_ntk),这个switch语句就是根据jj_ntk的值,来判定查询方法。由代码我们可以看出,主要由三种方法:PLUS、MINUS、NOT。由于我们以简单方法为例,ret的值并没有改变,返回默认值0。422 q = Clause(field);该方法实现分词功能。4221 Jj_2_1(2);javaCC生成的方法,判断是否为术语或者冒号。422

22、2 这里同样有一个switch (jj_ntk = - 1) ? jj_ntk)语句,不过它是用来判断字符类型的,根据不同的类型,进行不同的处理。分词涉及的类型很多,您可以从QueryParserConstants清楚地看出来。 查询的分词和索引时的分词是类似的。关于分词,我们将在分析器的专题中详细介绍,这里就不再累赘。最终返回的q便为分词的结果。它是Query类型,记录了每个Token的位置position、所属字段field、乘积因子boost、跨度slop和内容content等详细信息。423 AddClause(clauses, CONJ_NONE, mods, q);把每个Token

23、加入到ArrayList的对象当中。在这个方法中,涉及到几个判断。4231 if (clauses.Count 0 & conj = CONJ_AND),这是对于复合查询而言的,如果之前已有Token加入ArrayList对象中,并且之前与现在是与的关系,那么将现在的Token加入其中,并设置与的关系。由于这里是简单查询,不作详细说明。4232 if (clauses.Count operator_Renamed = AND_OPERATOR & conj = CONJ_OR),这也是对复合查询而言的。4233 if (operator_Renamed = OR_OPERATOR),用于判断当

24、前各个Token之间的逻辑关系。下面将根据required和prohibited两个参数的值,决定每个Token的与、或、非,然后将各个Token添加到ArrayList的对象clauses。4234 接下来的一个while循环,根据之前判定的查询方式、token间逻辑关系等参数,返回Query对象。在简单查询中,直接返回对象q。5Hits hits = searcher.Search(query);这是整个搜索过程的核心部分,前面的部分都是为该部分作准备。现在,索引文件信息存储在searcher中,用户输入字符串信息存储在query中,两个条件都具备了,可以开始查询了。查询的结果存放在Hit

25、s的对象hits当中。需要说明的是,Search有很多个重载方法,但最终都要调用Hits的构造函数实现查询工作。本文以构造函数Hits(Searcher s, Query q, Filter f)为例。其中s、q分别为上面传入的参数searcher、query,f为过滤器,这里默认为null。Hits(Searcher s, Query q, Filter f)的功能实现主要通过两个关键语句。51 weight = q.Weight(s);该方法主要计算权重,是查询结果的排序工作的依据之一。Weight是一个接口类,它存在的目的是使检索不改变一个Query,使得Query可以重用,即实现Que

26、ry对象的重复使用。511 Query query = searcher.Rewrite(this);实现query的重写。重写的目的是似的最终的query存放的是本次查询用户输入的信息,即第4部分返回的对象q。它的实现方法很简单,如果是第一次查询,则直接返回;如果不是第一次查询,则将本次查询对象赋值给query然后再返回。512 Weight weight = query.CreateWeight(searcher);该方法中,有一个判断语句if (terms.Count = 1),即如果只有一个token,那么由于不存在两个token之间的位置关系,可以直接计算权重,如果不止一个token

27、,那么调用方法PhraseWeight(this, searcher);this就是本次query。5121 PhraseWeight(this, searcher)该方法首先进行一些初始化工作,相似度等参数都采用默认的值。接着调用idf = similarity.Idf(Enclosing_Instance.terms, searcher)计算每个短语的得分因子idf。5122 float sum = weight.SumOfSquaredWeights();计算得分。5123 float norm = GetSimilarity(searcher).QueryNorm(sum);计算标准化

28、因子。5124 weight.Normalize(norm);对权重进行标准化处理。 关于各种因子的计算方法,请参考附件一。52 GetMoreDocs(50);返回查询结果得分最高的前100条。在lucene2.0当中,查询结果如果足够多,并不是一次性的全部返回,lucene默认先返回得分最高的100条,一般来讲,这100条已经能够满足用户的需求了;如果还不能满足用户的需求 ,根据用户需要,再返回得分次高的200条,接着400条依次类推,直到满足用户需求为止。该方法的实现如下: private void GetMoreDocs(int min) if (hitDocs.Count min) min = hitDocs.Count; int n = min * 2; / double # re

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1