当前位置:首页 > WEB开发 > Web前端

Lucene怎么控制segments的数量

优良自学吧提供Lucene怎么控制segments的数量,Lucene如何控制segments的数量? Lucene的索引文件,会包含很多个segments文件,每个segment中包含多个documents文件,一个segmen

Lucene如何控制segments的数量?

Lucene的索引文件,会包含很多个segments文件,每个segment中包含多个documents文件,一个segment中会有完整的正向索引和反向索引。
在搜索时,Lucene会遍历这些segments,以segments为基本单位独立搜索每个segments文件,而后再把搜索结果合并。

建立索引文件的过程,实际就是把documents文件一个个加入索引中,Lucene的做法是最开始为每个新加入的document独立生成一个segment,放在内存中。而后,当内存中segments数量到达一个阙值时,合并这些segments,新生成一个segment加入文件系统的segments列表中。
而当文件系统的segments数量过多时,势必影响搜索效率,因此需要不断合并这些segments文件。

那么Lucene的合并策略是什么?如何保证合适的segments数量呢?

其实Lucene有两套基本的策略:
第一种策略实现代码位于IndexWriter#optimize()函数,其实就是把所有segments文件合并成一个文件。合并的算法是递归合并列表最后的mergeFactor个segments文件直到合并成一个文件。这儿mergeFactor是Lucene的一个参数。
btw: 从算法细节上看,其实我不是喜欢这段实现,因为列表的最后mergeFactor个文件内容实际被扫描了segmens_count/mergeFactor次。如果分段归纳合并的方式不知道是否更好,每个segment文件内容都将被扫描 ceil(Log_mergeFactor(segmens_count)) 或ceil(Log_mergeFactor(segmens_count)) +1次,是否更好?

第二种策略实现代码位于IndexWriter#maybeMergeSegments()函数中,这个代码就复杂了,它的基本策略就是要求确保合并后两个公式的成立:
假定segments是个有序列表,B表示maxBufferedDocs,f(n)=ceil(log_M(ceil(n/B))),M表示mergeFactor,这儿maxBufferedDocs和mergeFactor是两个参数
1. 如果第i个segment的documents数量为x,第i+1个segment的documents数量为y,那么f(x)>f(y)一定成立
2. f(n)值相同的segments的数量不得超过M。
那么maybeMergeSegments()函数是如何确保这两个公式成立的呢?
1.首先,从代码:

protectedfinalvoidmaybeFlushRamSegments()throwsIOException{
//Aflushistriggeredifenoughnewdocumentsarebufferedor
//ifenoughdeletetermsarebuffered
if(ramSegmentInfos.size()>=minMergeDocs
||numBufferedDeleteTerms>=maxBufferedDeleteTerms){
flushRamSegments();
}
}

这儿minMergeDocs=maxBufferedDocs, 因此可以看出,当内存中缓存的segments被合并写回磁盘时生成的segment的document count等于或小于maxBufferedDocs(即minMergeDocs)。
补充:因为maybeMergeSegments()运行在同步代码中,因此只要ramSegmentInfos.size==minMergerDocs(即maxBufferedDocs)就会写回磁盘,因此应该不存在ramSegmentInfos.size>maxBufferedDocs才写回的情况。而且,但如果是这种情况,因为合并后的segment文件的document count过大,后面的maybeMergeSegments()将不做合并处理直接退出,上述公式就可能不成立,那么算法将有错。
----
2.
2.1 因此maybeMergeSegments()第一次执行时,所有segments的document count都小于等于maxBufferedDocs。此时,从i=0开始,合并i~i+mergeFactor-1个文件,如果合并后的doc count>maxBufferedDocs时,保留第i个segment,否则继续合并改变后的i~i+mergeFactor-1,直到doc count>maxBufferedDocs或所有segments文件个数已经<mergeFactor了。经过这样一轮的合并,除了最后<mergeFactor个的doc counts<=maxBufferedDocs文件外,其它文件的doc counts一定都>maxBufferedDocs并<maxBufferedDocs*mergeFactor了。
2.2 这时,不理会最后<mergeFactor个doc count<maxBufferedDocs的文件,而后按2.1的同理规则,合并之前的文件,让这些文件的最后<mergerFactor个segment符合 maxBufferedDocs<doc counts<=maxBufferedDocs*mergeFactor,之前的segment文件都符合maxBufferedDocs*mergeFactor<doc counts<=maxBufferedDocs*mergeFactor^2
2.3 重复2.2,最后得到的列表就会满足上述两等式的成立
---
3
之后,每次从内存缓存中flush出一个新的segment时,也就是往这个segments列表的最后增加一个doc_count<=maxBufferedDocs的文件,同样执行上述步骤2进行合并,能够始终保证上述两公式的成立。
----
4
4.1
IndexWriter#addIndexesNoOptimize同样借鉴使用了maybeMergeSegments()算法,区别此时,实际是已有一个符合两公式的segments序列T,在T之后追加上随意顺序的segments序列S。这时,我们先找到S中doc count值最大的那个segment,计算出它属于的区间f(x),使得maxBufferedDocs*mergeFactor^x<doc counts<=maxBufferedDocs*mergeFactor^(x+1),而后按2.2的算法合并出除了最后<mergerFactor个segments外, 之前所有segments都符合 a. doc count>maxBufferedDocs*mergeFactor^(x+1) b.符合上述2等式。
btw: 因为这儿调用IndexWriter#addIndexesNoOptimize传入的参数是maxBufferedDocs*mergeFactor^(x+1),因为S所有segment的doc count都一定小于maxBufferedDocs*mergeFactor^(x+1),因此S的所有元素都会参与收缩合并。
4.2 将最后<mergerFactor个doc count<maxBufferedDocs*mergeFactor^(x+1)的segments合并,如果合并后的segment的doc count大于maxBufferedDocs*mergeFactor^(x+1),就继续2.2步骤,使得整个队列符合上述两公式
-----

上述两种策略,最终确保了Lucene中的segments不会太多,确保效率。

BTW:实际上,如果documents太多时,Lucene还支持把docuements分成几个组,每个组用独立的进程或电脑进行索引,而后再多个目录的索引合并起来,具体可参考IndexWriter#addIndexesNoOptimize和IndexWriter#addIndexes函数

lucene主要有两种文档模型:document和field,一个document可能包含若干个field。

每一个field有不同的策略:

1.被索引 or not,将该字段(field)经过分析(analyise)后,加入索引中,并不是原文。

2.如果被索引,可选择是否保存“term vector”(向量),用于相似检索。

3.可选择是否存储(store),将原文直接拷贝,不做索引,用于检索后的取出。

lucene中的文档模型类似于数据库,但是又不完全相同,体现在如下几方面:

1.无规范格式,即无需固定的schema,无列等预先设计,同一个索引中加入的document可包含不同的field。

2.非正规化,lucene中的文档模型是一个平面化的结构,没有递归定义,自然连接等等复杂的结构。

2.2 理解索引过程

总体来说,索引过程为:

1.提取摘要:从原文提取,并创建document和field对象。tika提供了pdf、word等非文本的文本提取。

2.分析:analysis,首先对document的field进行分解,产生token流,然后经过一系列filter(如小写化)等。

3.建立索引:通过indexwriter的adddocument写入到索引中。lunece使用了反向索引,即“那个document包含单词x”,而不是“document包含哪些word”

索引文件组成

为了保证效率,每个索引由若干segments组成:

_x.cfs 每个segments由若干个cfs组成,x为0,1,2….如果开启了usecompoundfile,则只有一个.cfs文件。

segments_<n>:记载每个分区对应的cfs文件。

每个一段时间后,在调用indexwriter时,会自动合并这些segment

2.3 索引的基本操作

首先创建indexwriter

indexwriter(dir,new whitespaceanalyser(),indexwriter.maxfield.unlimited);

dir是索引的保存路径,whitespaceanalyser是基于空白的分词,最后部限定field的数量。

依次创建文档document和field

document doc = new document();

doc.add(new filed(key,value,store?,index?)

key就是field的检索字段名,value就是待写入/分析的文本。

store,与索引无关,是否额外存储原文,可以在搜索结果后调用出来,no不额外存储;yes,额外存储。

index,no,不索引;analyzed,分词后索引;not_analyzed,不分词索引;analyzed_no_norms,分词索引,不存储norms;not_analyzed_no_norms,不分词,索引,不存储norms。除了no外都算索引,可以搜索。norms存储了boost所需信息,包含了norm可能会占用更多内存?

删除索引

indexwriter提供了删除document的功能:

deletedocumen(term)

deletedocumen(term[])

deletedocumen(query)

deletedocumen(query [])

特别注意term不一定是唯一的,所以有可能误删除多个。另外最好选择唯一的、非索引的term以防混乱(比如唯一id)。

删除后commit()然后close才能真正写入索引文件中。

删除后只是标记为删除,maxdoc()返回所有文档(含已经删除,但未清理的);numdocs:未删除的文档数量

使用delete后,再optimize():压缩删除的空间、再commit才真正的删除释放空间。

更新索引

updatedocument(term,document),lunce只支持全部替换,即整个docuemnt要被替换掉,没法更新单独的field。

2.4 field的选项

选项分为三类:index、store和term vector。

index选项

index.analyzed :分词后索引

index.not_analyzed : 不分词直接索引,例如url、系统路径等,用于精确检索

index.analyzed_no_norms : 类似index.analyzed,但不存储norm terms,节约内存但不支持boost。

index.not_analyzed_no_norms : 类似index.not_analyzed,但不存储norm terms,节约内存但不支持boost,非常常用

index.no : 根本不索引,所以不会被检索到

默认情况,luncene会存储所有单词的出现位置,可以用field.setomittermfreqandpositions(true)关闭,但是会影响phrasequery和spanquery。

store选项

store.yes :存储原始value数值,可在检索后被提取

store.no :不存储原始数值,检索后无法重新提取。

compressiontools 可用于压缩、解压缩byte数组。

term vector选项

term vector主要用于为相似搜索提供支持,例如搜索cat,返回cat。

termvector.yes :记录term vector

termvector.with_positions :记录term vector以及每个term出现的位置

termvector.with_offsets :记录term vector以及每个term出现的偏移

termvector.with_positions_offsets :记录term vector以及出现的位置+偏移

termvector.no :不存储termvector

如果index选择了no,则termvector必须选择no

将string外的类型作为field的数据源

reader:无法被store,默认tokenstream始终被分词和索引。

tokenstream:分词之后的结果作为源,无法被store,始终analyzed并索引。

byte[] :无法被索引,没有termvector,必须被store.yes

与排序相关选项

数字field可以用numericfield,如果是文本field必须field.index.not_analyzed,才能排序,即保证这个field只含有一个token才能排序

多值field(multi-valued fields)

比如一本书有多个作者,怎么办呢?

一种方法是,添加多个同一key,不同value的field

document doc = new document();
for (int i = 0; i < authors.length; i++) {
doc.add(new field(“author”, authors[i],
field.store.yes,
field.index.analyzed));
}

还有一种方法在第4章中提出。

2.5 boost(提升)

boost可以对影响搜索返回结果的排序

boost可以在index或者搜

solr索引

当我们真正进入到Lucene源代码之中的时候,我们会发现:

Lucene的索引过程,就是按照全文检索的基本过程,将倒排表写成此文件格式的过程。

Lucene的搜索过程,就是按照此文件格式将索引进去的信息读出来,然后计算每篇文档打分(score)的过程。

lucene的工作方式

lucene提供的服务实际包含两部分:一入一出。所谓入是写入,即将你提供的源(本质是字符串)写入索引或者将其从索引中删除;所谓出是读出,即向用户提供全文搜索服务,让用户可以通过关键词定位源。

l写入流程

源字符串首先经过analyzer处理,包括:分词,分成一个个单词;去除stopword(可选)。将源中需要的信息加入Document的各个Field中,并把需要索引的Field索引起来,把需要存储的Field存储起来。将索引写入存储器,存储器可以是内存或磁盘。

l读出流程

用户提供搜索关键词,经过analyzer处理。对处理后的关键词搜索索引找出对应的Document。用户根据需要从找到的Document中提取需要的Field。

索引文件结构

Lucene的索引结构在概念上即为传统的倒排索引结构。下图就是Lucene生成的索引的一个实例:

Lucene的索引结构是有层次结构的,主要分以下几个层次:

索引(Index):

o 在Lucene中一个索引是放在一个文件夹中的。

o 如上图,同一文件夹中的所有的文件构成一个Lucene索引。

段(Segment):

o 一个索引可以包含多个段,段与段之间是独立的,添加新文档可以生成新的段,不同的段可以合并。

o 如上图,具有相同前缀文件的属同一个段,图中共两个段"_0"和"_1"。

o segments.gen和segments_5是段的元数据文件,也即它们保存了段的属性信息。

文档(Document):

o 文档是我们建索引的基本单位,不同的文档是保存在不同的段中的,一个段可以包含多篇文档。

o 新添加的文档是单独保存在一个新生成的段中,随着段的合并,不同的文档合并到同一个段中。

域(Field):

o 一篇文档包含不同类型的信息,可以分开索引,比如标题,时间,正文,作者等,都可以保存在不同的域里。

o 不同域的索引方式可以不同,在真正解析域的存储的时候,我们会详细解读。

词(Term):

词是索引的最小单位,是经过词法分析和语言处理后的字符串。

Field有两个属性可选:存储和索引。通过存储属性你可以控制是否对这个Field进行存储;通过索引属性你可以控制是否对该Field进行索引。这看起来似乎有些废话,事实上对这两个属性的正确组合很重要,下面举例说明:

还是以刚才的文章为例子,我们需要对标题和正文进行全文搜索,所以我们要把索引属性设置为真,同时我们希望能直接从搜索结果中提取文章标题,所以我们把标题域的存储属性设置为真,但是由于正文域太大了,我们为了缩小索引文件大小,将正文域的存储属性设置为假,当需要时再直接读取文件;我们只是希望能从搜索解果中提取最后修改时间,不需要对它进行搜索,所以我们把最后修改时间域的存储属性设置为真,索引属性设置为假。

倒排索引

索引技术主要有以下3种:倒排索引,后缀数组和签名文件。其中,倒排索引技术在当前大多数的信息检索系统中得到了广泛的应用,它对于关键词的搜索非常有效,在lucene中也是使用的这种技术。后缀数组技术在短语查询中具有很快的速度,但是这样的数据结构在构造和维护时都比较复杂一些。签名文件技术在20世纪80年代比较流行,但是后来倒排索引技术逐渐超越了它。

倒排索引是目前搜索引擎公司对搜索引擎最常用的存储方式,也是搜索引擎的核心内容,倒排索引源于实际应用中需要根据属性的值来查找记录。这种索引表中的每一项都包括一个属性值和具有该属性值的各记录的地址。由于不是由记录来确定属性值,而是由属性值来确定记录的位置,因而称为倒排索引。倒排索引是以关键字和文档编号结合,并以关键字作为主键的索引结构。下面利用一个例子来说明倒排索引:

比如说有两个文档,doc1和doc2他们的内容分别如下:

Doc1:wearestudents。

Doc2:Areyoustudent?

如果按照正常的索引建立如下所示:

文档名关键字次数

Doc1we1

Doc1are1

Doc2student1

Doc2Are1

……

这里索引的建立是以文档为标准的,这样当文档很多

的时候数据量将非常的大,检索效率会明显下降的。倒排索引是以单词为标准来进行索引的建立的。还以上面的doc1和doc2为例:

关键字出现的文档次数

studentdoc21

wedoc11

Aredoc1doc211

……

索引建立

你可能已经注意到,即使solr.xml已经被POST到服务器两次,但你搜索"solr"时仍然只得到一个结果。这是因为schema.xml例子文件指定了一个"uniqueKey"字段作为"id"。无论何时你向Solr发送指令添加一个文档,如果已经存在一个uniqueKey相同的文档,它会自动地为你替换。

Solr建立索引和对关键词进行查询都得对字串进行分词,在向索引库中添加全文检索类型的索引的时候,Solr会首先用空格进行分词,然后把分词结果依次使用指定的过滤器进行过滤,最后剩下的结果才会加入到索引库中以备查询。分词的顺序如下:

l索引

1:空格whitespaceTokenize

2:过滤词StopFilter

3:拆字WordDelimiterFilter

4:小写过滤LowerCaseFilter

5:英文相近词EnglishPorterFilter

6:去除重复词RemoveDuplicatesTokenFilter

l查询

1:查询相近词

2:过滤词

3:拆字

4:小写过滤

5:英文相近词

6:去除重复词

在FieldType定义的时候最重要的就是定义这个类型的数据在建立索引和进行查询的时候要使用的分析器analyzer,包括分词和过滤。在例子中FieldType在定义的时候,在index的analyzer中使用solr.WhitespaceTokenizerFactory这个分词包,就是空格分词,然后使用

solr.StopFilterFactory(去掉如下的通用词,多为虚词。

"a","an","and","are","as","at","be","but","by",

"for","if","in","into","is","it",

"no","not","of","on","or","s","such",

"t","that","the","their","then","there","these",

"they","this","to","was","will","with"),

solr.WordDelimiterFilterFactory,关于分隔符的处理。

solr.RemoveDuplicatesTokenFilterFactory避免重复处理。

solr.StandardFilterFactory移除首字母简写中的点和Token后面的’s。仅仅作用于有类的Token,他们是由StandardTokenizer产生的。

例:StandardTokenizer+StandardFilter

"I.B.M.cat'scan't"==>"IBM","cat","can't"

这几个过滤器。在向索引库中添加类型的索引的时候,Solr会首先用空格进行分词,然后把分词结果依次使用指定的过滤器进行过滤,最后剩下的结果才会加入到索引库中以备查询。

索引存储

1.前缀后缀规则(Prefix+Suffix)

Lucene在反向索引中,要保存词典(TermDictionary)的信息,所有的词(Term)在词典中是按照字典顺序进行排列的,然而词典中包含了文档中的几乎所有的词,并且有的词还是非常的长的,这样索引文件会非常的大,所谓前缀后缀规则,即当某个词和前一个词有共同的前缀的时候,后面的词仅仅保存前缀在词中的偏移(offset),以及除前缀以外的字符串(称为后缀)。

比如要存储如下词:term,termagancy,termagant,terminal,

如果按照正常方式来存储,需要的空间如下:

[VInt=4][t][e][r][m],[VInt=10][t][e][r][m][a][g][a][n][c][y],[VInt=9][t][e][r][m][a][g][a][n][t],[VInt=8][t][e][r][m][i][n][a][l]

共需要35个Byte.

如果应用前缀后缀规则,需要的空间如下:

[VInt=4][t][e][r][m],[VInt=4(offset)][VInt=6][a][g][a][n][c][y],[VInt=8(offset)][VInt=1][t],[VInt=4(offset)][VInt=4][i][n][a][l]

共需要22个Byte。

大大缩小了存储空间,尤其是在按字典顺序排序的情况下,前缀的重合率大大提高。

2.差值规则(Delta)

在Lucene的反向索引中,需要保存很多整型数字的信息,比如文档ID号,比如词(Term)在文档中的位置等等。

由上面介绍,我们知道,整型数字是以VInt的格式存储的。随着数值的增大,每个数字占用的Byte的个数也逐渐的增多。所谓差值规则(Delta)就是先后保存两个整数的时候,后面的整数仅仅保存和前面整数的差即可。

比如要存储如下整数:16386,16387,16388,16389

如果按照正常方式来存储,需要的空间如下:

[(1)000,0010][(1)000,0000][(0)000,0001],[(1)000,0011][(1)000,0000][(0)000,0001],[(1)000,0100][(1)000,0000][(0)000,0001],[(1)000,0101][(1)000,0000][(0)000,0001]

供需12个Byte。

如果应用差值规则来存储,需要的空间如下:

[(1)000,0010][(1)000,0000][(0)000,0001],[(0)000,0001],[(0)000,0001],[(0)000,0001]

共需6个Byte。

大大缩小了存储空间,而且无论是文档ID,还是词在文档中的位置,都是按从小到大的顺序,逐渐增大的。

索引压缩

为了减小索引文件的大小,Lucene对索引还使用了压缩技术。首先,对词典文件中的关键字进行了压缩,关键字压缩为<前缀长度,后缀>。例如:当前词为马来西亚语,上一个词为马来西亚,那么马来西亚语压缩为<4,语>。其次大量用到的是对数字的压缩,数字只保存与上一个值的差值(这样可以减小数字的长度,进而减少保存该数字需要的字节数)。例如,当前文章号是14569(不压缩要用3个字节保存),上一文章号是145704,压缩后保存5(只用一个字节)。

Lucene的域数据文件(.fdt文件)在一定情况下采用了ZLIB压缩算法,这是一种无损的数据压缩格式,且独立于具体的CPU类型、操作系统、文件格式以及字符集。但是它的弱点是对压缩数据不支持随机访问。在Lucene中是通过调用JDK库文件中的Deflater类来实现ZLIB压缩的(参见index包下的FieldsWriter类)。

差值压缩(deltacompression)是Lucene广泛采用的另一种压缩方式,这一方法是基于排序的字符通常具有相同的前缀部分,只把一个块中与第一个词不同的部分存储在索引里显然能够节省存储空间。例如第一个单词位“automata”8个字符,接下来的单词“automate”也有8个字符,下一个单词“automatic”9个字符,再下一个单词“automation”10个字符在存储的时候按如下的方式存储:8{automat}a1<>e2<>ic3<>ion。其中的数字表示与前一个单词不同的个数。

索引优化

利用Lucene,在创建索引的工程中你可以充分利用机器的硬件资源来提高索引的效率。当你需要索引大量的文件时,你会注意到索引过程的瓶颈是在往磁盘上写索引文件的过程中。为了解决这个问题,Lucene在内存中持有一块缓冲区。但我们如何控制Lucene的缓冲区呢?幸运的是,Lucene的类IndexWriter提供了三个参数用来调整缓冲区的大小以及往磁盘上写索引文件的频率。

1.合并因子(mergeFactor)

这个参数决定了在Lucene的一个索引块中可以存放多少文档以及把磁盘上的索引块合并成一个大的索引块的频率。比如,如果合并因子的值是10,那么当内存中的文档数达到10的时候所有的文档都必须写到磁盘上的一个新的索引块中。并且,如果磁盘上的索引块的隔数达到10的话,这10个索引块会被合并成一个新的索引块。这个参数的默认值是10,如果需要索引的文档数非常多的话这个值将是非常不合适的。对批处理的索引来讲,为这个参数赋一个比较大的值会得到比较好的索引效果。

2.最小合并文档数

这个参数也会影响索引的性能。它决定了内存中的文档数至少达到多少才能将它们写回磁盘。这个参数的默认值是10,如果你有足够的内存,那么将这个值尽量设的比较大一些将会显著的提高索引性能。

3.最大合并文档数

这个参数决定了一个索引块中的最大的文档数。它的默认值是Integer.MAX_VALUE,将这个参数设置为比较大的值可以提高索引效率和检索速度,由于该参数的默认值是整型的最大值,所以我们一般不需要改动这个参数。

通过表1,你可以清楚地看到三个参数对索引时间的影响。在实践中,你会经常的改变合并因子和最小合并文档数的值来提高索引性能。只要你有足够大的内存,你可以为合并因子和最小合并文档数这两个参数赋尽量大的值以提高索引效率,另外我们一般无需更改最大合并文档数这个参数的值,因为系统已经默认将它设置成了最大。

优化索引就是把磁盘上的多个索引文件合并在一起,以便减少文件的数量,从而也减少搜索索引的时间。需要注意的是索引优化并不能提高索引的速度,而只能提高搜索的速度;并且索引优化只有在索引处理完在一定时间不会发生变化的时候进行。

Lucene采用在内存中缓存多个文档,在写入磁盘前把这些文档合并为段。并且可以通过mergeFcatormaxMergeDocsminMergeDocs控制所要合并的文档的数量。mergeFactor是用于控制Lucene在把索引从内存写入磁盘上的文件系统时内存中最大的Document数量、同时它还控制内存中最大的Segment数量。mergeFactor这个参数设置会严重影响到Lucene建立索引时花费的词盘I/O时间和内存使用量,如果mergeFactor值设置的太小,则磁盘的I/O操作太频繁,经常进行Segment的合并。而如果mergeFactor值设置的太大,则内存中持有的Document数量可能会很多,因此占用大量的内存。maxMergeDocs用来限制一个Segment中最大的文档数量。例如:当mergeFactor设置为10maxMergeDocs设置为2000是,第一次合并,Segment中的文档数量可能为100,再合并时,一个Segmnet中的文档数量就会为1000,此时由于受到maxMergeDocs的限制,一个Segment中的文档数量最多不超过2000,因此下一次合并将发生在2000文档时。minMergeDocs用于控制内存中持有的文档数量,也就是说,内存中文档被到磁盘前的数量。

Lucene可以通过FSDirectory把索引存储在磁盘目录中,也可以通过RAMDirectory使用内存缓冲的形式操作索引文件,以便进一步控制索引的合并。RAMDirectory的操作与FSDirectory的操作类似,但是速度更快,并且RAMDirectory不把具体的索引写入磁盘目录,一旦程序退出,索引文件就不存在。为此Lucene提供了addIndexes函数把内存索引文件写入磁盘目录文件。

commit就是提交数据,就是更新。

curl'http://localhost:8983/solr/update?optimize=true&maxSegments=10&waitFlush=false'

索引提交

这个设置用于控制什么时候将更新的数据写入索引,该设置由以下两个子参数

maxDocs当索引的文档达到这个数量时,就自动更新到索引中

maxTime单位为毫秒,当离上一次commit超过这个时间后,将自动最近更新的文档写入索引中

只要达到上面任一条件,solr都将自动最近更新的文档写入索引中,如果没有指明autoCommit这个参数,只能通过显示调用commit才能将最近更新的文档写入索引中。设置这个参数时,就需要最性能和准确度之间做个权衡,频繁提交,可以提高数据准确性,但是对性能有一定的损耗。

<autoCommit>

<maxDocs>10000</maxDocs>

<maxTime>1000</maxTime>

</autoCommit>

建立索引:堆排序,hashjoin

最简单的能完成索引的代码片断

IndexWriterwriter=newIndexWriter(“/data/index/”,newStandardAnalyzer(),true);

Documentdoc=newDocument();

doc.add(newField("title","luceneintroduction",Field.Store.YES,Field.Index.TOKENIZED));

doc.add(newField("content","luceneworkswell",Field.Store.YES,Field.Index.TOKENIZED));

writer.addDocument(doc);

writer.optimize();

writer.close();

下面我们分析一下这段代码。

首先我们创建了一个writer,并指定存放索引的目录为“/data/index”,使用的分析器为StandardAnalyzer,第三个参数说明如果已经有索引文件在索引目录下,我们将覆盖它们。

然后我们新建一个document。

我们向document添加一个field,名字是“title”,内容是“luceneintroduction”,对它进行存储并索引。

再添加一个名字是“content”的field,内容是“luceneworkswell”,也是存储并索引。

然后我们将这个文档添加到索引中,如果有多个文档,可以重复上面的操作,创建document并添加。

添加完所有document,我们对索引进行优化,优化主要是将多个segment合并到一个,有利于提高索引速度。

随后将writer关闭,这点很重要。

索引查看

http://localhost:8983/solr/admin/luke?wt=xslt&tr=luke.xsl

类似ikjar包的配制方法,在solrconfig.xml中加入<requestHandlername="/admin/luke"class="org.apache.solr.handler.admin.LukeRequestHandler"/>

会展示索引字段field有哪些以及它的fieldtype和数量、是否存储等信息。


(本文来自互联网,不代表搜站(http://www.ylzx8.cn/)的观点和立场)
本站所有内容来自互联网,若本站收录的信息无意侵犯了贵司版权,请给我们来信(ylzx8cn@163.com),我们会及时处理和回复,谢谢