1、对于按创建时间的排序可以使用doc.id的方式
new SortField(null, SortField.DOC, reverse)排序方式尽量使用INT类型的字段
也就是按照写入索引的顺序排序
2、对于时间字符串的排序可以转换成整数进行排序
3、去掉不必要的parse
使用TermQuery替换
4、TermQuery和Term可以只保留一个实例
createTerm(text)
5、减少Doc到model的转换
索引出来String到Date的转换多余而且费时
直接使用Doc对象包装成JSONObject
6、MultiFieldQueryParser改成自己用boolean查询重构
7、减少请求参数的包装类
8、搜索排序方法可以作为常量
将sort参数变成int型,使用swich进行判断
10、使用HitCollector类来适应不同情况下,Hits的大小
新、旧接口
相关搜索接口
11、使用尽可能快的磁盘IO
12、日志,先写文件,每天批量入库
13、增量索引使用reopen
新的reopen()方法只会加载那些变更过的索引片断,而不是重新加载完整的索引。
14、setMergeFactor 在做实时索引的时候,可以设置的小一点
这样就会及时索引进去
增量更新 (只需将 create 参数设为 false,即可往现有索引库添加新数据。
IndexWriter writer = new IndexWriter(directory, analyzer, false);
1,使用indexreader创建indexsearcher.
2,indexsearcher在使用完了以后不要关闭.
3.使用indexreader.isCurrent()判断索引是否被indexwriter改动.
4,如果索引被改动,indexsearcher.close()先前那个,然后new indexsearcher(indexreader).
增量BUILD的解决安案情:
1。
其中在每个检索方法里构建代码如下:
Directory directory = FSDirectory.getDirectory(DocumentIndexerImpl.getIndexSavePath());
IndexSearcher isearcher = new IndexSearcher(directory);
IndexReader reader = IndexReader.open(directory);
在检索完之后有:
isearcher.close();
reader.close();
可会导致每次检索进入这个方法都要进行一次IO操作。
2.
传string给searcher,searcher会维护一个内部的reader,当本次搜索结束后reader会被关掉.如果使用reader构造,reader在本次搜索结束后不会被关掉,除非你自己调用reader.close();所以用reader去构造searcher,然后通过searcher.getIndexReader()获取当前的reader,用reader.iscurrent()判断索引文件是否变化了,如果索引文件已经更改,则把当前的searcher关闭,然后再利用reader.reopen()方法获取新的reader,再创建一个searcher,像这样,new IndexSearcher(reader.reopen());
代码:
一、indexSearcher=new IndexSearcher(IndexReader.open(indexPath));
二、/*
* 先获取reader,如果索引文件已经变化,关闭当前indexSearcher,然后以重新获取的indexReader
* 作为参数new一个新的indexSearcher实例
*/
IndexReader indexReader=indexSearcher.getIndexReader();//获取当前的indexReader
if(!indexReader.isCurrent()){//判断是否有索引更新
// 如果有索引更新,先关闭当前的indexSearcher
indexSearcher.close();
//利用indexReader.reopen()获取新的indexReader,并作为IndexSearcher的参数创建一个新的indexSearcher
indexSearcher=new IndexSearcher(indexReader.reopen());
}
一个索引只能有一个indexreader。
首先判断 lastmodify时间,如果被更新了则, new 一个IndexReader, 否则就直接返回null,
而操作方法都扔给了用户. 所以官方所谓的reopen能减少消耗说法并不准确,它做的只是在改变时重新连接,
但这个他官方文档所说的只更新更新部分有很大不同,现在只是选择性地降低了io,
但是如果每次探测时索引都变了就变得没有意义,这样的好处是,索引的跟踪可以变得更频繁,也不再需要程序过多干预了.
Lucene2.3.2的变更
Author: Jeremy Chow(coderplay@gmail.com)
Last Modified: Aug 1st, 2008
一、运行时
1. IndexWriter最大化地提高了现有的索引速度。第一,IndexWriter现在由内存的使用情况来决定刷新索引至磁盘,而不是之前用IndexWriter.setMaxBufferedDocs规定缓存的Docuement数量来决定刷新行为。第二,ConcurrentMergeScheduler使用后方(backgroud)线程(调用IndexWriter.setMergeScheduler (new SerialMergeScheduler())保持向下兼容) 来进行合并操作,由此得到的好处是合并行为不会阻塞IndexWriter.addDocument操作。第三,现在对segment的合并操作是依据每个segment大小,而不再是依据它们所包含Document的数量。
2. SortField.AUTO对long型起作用。在之前的lucene版本中,为排序自动检测Field类型时,数字首先被解释成int,如果解释失败,则认为是float。现在则先检测是否int,然后是否long,最后是float。
二、API 的变更
1. 新加了IndexWriter.setRAMBufferSizeMB(...),IndexWriter当缓存的Documents容量大于指定内存大小时进行刷新。同时,Token也添加了新的API,使用户使用char[]结合偏移量与长度来表示token (避免为每个Token调用一次new String ())。
三、新特性
1. 新加了IndexReader.reopen() 方法用来重新打开已经存在的IndexReader。
2. 新加了IndexWriter.optimize(int maxNumSegments) 用来局部优化值小于maxNumSegments 的片段
3. 新加了IndexWriter.optimize(int maxNumSegments) 局部优化索引
4. 新加了IndexCommit.isOptimized()。
5. 新加了TokenFilter.reset()。
四、优化
1. CachingTokenFilter 现在使用一个迭代器来访问缓存在LinkedList内的Tokens。显著地提升了性能,特别是在Tokens数目比较大的情况。
2. 从实质上优化了IndexWriter怎么使用RAM来缓存Documents,使索引速度加快到之前的2~8倍。现在使用了一个简单的共享散列表记录在内存中的Postings。一个Term对应一个posting。这个表直接写入到一个segment中。
3. 消除了偶尔会发生在复合文件(compound files)上的缓存到缓存拷贝(buffer to buffer copy)。
4. 去掉了Document中的同步机制,实际就是把存储Fields的Vector改成了ArrayList。
5. StandardTokenizer (StandardAnalyzer)使用JFlex代替JavaCC生成Tokenizer,使其速度是以前的6倍。
6. 使用bulk-coping技术拷贝原始字节,加速邻接的未删除文档的合并。
7.加速了 ISOLatin1AccentFilter 。
五、重新打开索引文件
IndexReader .reopen()
如果IndexReader实例调用此方法时,索引有变化,则生成一个新的IndexReader实例。
打开索引是非常昂贵的操作。此方法可以用来刷新已经存在的IndexReader,减少代价。此方法尝试只加载已经变化或新建立的片段(segement)。
如果索引自从打开后没有变化,则返回原来的IndexReader对象,否则会返回一个新的IndexReader对象。此时旧的IndexReader对象没有 关闭,只是不可用。
注意: 新打开的IndexReader对象可能会与旧的对象共享资源,据此,千万不要调用这些对象对索引的任何修改操作(例如:deleteDocument(int) , setNorm(int, String, byte) ),除非旧IndexReader对象已经关闭。否则,其行为将是不可确定的。
你可以通过比较返回的IndexReader与原来的IndexReader来判断其是否真的重新打开了:
IndexReader reader = ...
...
IndexReader new = r.reopen();
if (new != reader) {
... // reader was reopened
reader.close();
}
reader = new;
...
六、建立索引优化原理
以DocumentsWriter代替了之前的DocumentWriter。前者接受多个文档(Documents)的添加,并且直接把它们写入到一个单一的片段(segment)中。它比lucene2.2.0中用DocumentWriter为每个文档建立一个片段,然后将这些片段合并的方法更高效。
当加一篇文档时,它所存储的属性(Field)和词条向量(Term Vector)立即被写入到磁盘目录(假设不用RAM)。词频freq/prox 等词条信息(Posting),以词条为键值加入到Posting散列中。Posting散列表的每项维护着一个词频和prox组成的独立字节流。它包含多个文档的Posting数据。如果启用了向量,则为每个文档的每条词条都分配一个Posting向量(Posting Vector)。向量的每个元素记录词条的偏移量、位置等信息。
当Posting散列已满(假设使用RAM)或者加入到RAM的文档数目足够大(在此,我们用文档数目,而不是RAM使用量来刷新索引)时,我们会建立一个真实的片段,把它刷新到磁盘,然后重置Posting散列。
加入文档时,我们首先由属性(Field)名来组织文档所有的属性,并为每个属性记录其Posting散列。处理完每个属性后,我们刷新它的词条向量。当到整个片段的时候,我们首先通过名称将属性(fields)排序,然后依次排序每个属性的Postings。
线程:
多条线程可以同时调用addDocument方法。DocumentsWriter内部有一个getThreadState的同步调用,它为当前线程式分配一个ThreadState对象。无论何时,同一线程将会得到同一ThreadState。因此,如果各线程为各自不同的内容建立索引,则可以更有效地使用RAM。之后,processDocument会在那个ThreadState之上被调用,它不用作同步(很多消耗在这一步)。这是lucene2.3.0最重要的改进。 最后,同步调用finishDocument刷新变化至磁盘目录。
每个ThreadState实例都有属于其自身的Postng散列。当我们使用过多RAM时,会通过合并多个线程状态(ThreadSate)中相同词条的Posting表中的文档ID(docIDs),刷新所有线程的Posting散列至一个片段中。
当IndexWriter调用刷新操作(flush),且autoCommit=false时,会执行刷新。此时,我们强制所有线程空闲,且确定它们都空闲后才刷新。这意味着,你可以由一个给定的线程调用刷新操作。
七、建索引速度测试
CPU: Intel Dual CPU 2.00GHz,
内存: 1G DDR400
文本材料大小 : : 43.9 MB
文件数目 : 19997 个
分析器 : lucene 标准 StandardAnalyzer
Lucene 版本: 2.2.0
生成索引大小 : : 16,901,638 字节
耗时:
158094 微秒
110437 微秒
106328 微秒
Lucene 版本: 2.3.2
生成索引大小 : 16,177,772 字节
默认 16M 缓存耗时 :
15407 微秒
15500 微秒
设置 64M 缓存耗时 :
13578 微秒
13984 微秒
13359 微秒
15500 微秒
可以看出 2.3 比 2.2 建索引的速度要快 5~10 倍。 (不过现在看来是因为StandardAnalyzer变快了. )
索引过程中的任意时刻、任意进程都能对索引文件进行优化,
而且这样做也不会损坏索引文件或使其不能被搜索,
但是在索引过程中对索引进行优化的做法并不值得提倡
。优化操作的最佳时机是在索引过程结束之后,
且当你确认在此后的一段时间内不会对索引文件进行更改的时候。在索引过程中进行优化只会使优化操作耗费更多的时间。
索引优化过程需要两倍于索引文件磁盘空间。
使用 IndexWriter.addIndexes(IndexReader[]) 和 IndexWriter.addIndexes(Directory[]) 合并索引库有什么不同?
使用 Directory[] 参数所需的文件句柄和内存较小,索引文件仅需打开一次,而使用 IndexReader[] 参数则需要打开所有的索引库。
分享到:
相关推荐
《Lucene 4.7.2 Demo:Java全文搜索引擎的核心技术探索》 Lucene,作为Apache软件基金会的一个开源项目,是Java平台上的一个全文搜索引擎库。它的主要功能是提供高效、可扩展的文本检索和分析能力。在4.7.2这个版本...
Lucene 的 API 设计得非常通用,可以方便地处理各种数据源,如文件或数据库记录,将其映射为类似于数据库表格的结构。每个需要索引的单元称为 `Document`,它由多个 `Field` 组成,每个 `Field` 表示文档中的不同...
### Lucene3源码分析知识点概述 #### 一、全文检索的基本原理 ##### 1....以上是对Lucene3源码分析的一些关键知识点总结,通过对这些概念和技术的理解,可以更好地掌握Lucene的工作原理及其应用。
2. **文档(Document)**:在Lucene中,一个文档代表要被搜索的信息源,可以是网页、电子邮件、数据库记录等。文档由多个字段(Field)组成,每个字段有特定的名称和内容。 3. **字段(Field)**:字段是文档的组成...
Lucene的设计核心是索引机制,它将信息存储为一系列索引文件,这些文件的结构设计得十分通用,类似于数据库的表、记录和字段。这使得Lucene能够方便地与传统的文件或数据库系统进行映射,被视为支持全文检索的...
除了核心模块,Lucene还提供了一些附加功能,如 SpellChecker(拼写检查)、Highlighter(高亮显示搜索结果)和Remote搜索支持。在源码中,你可以找到对应的实现类,如SpellChecker、Highlighter等。 这个压缩包中...
通过lucene,你可以快速地在大量文本数据中找到匹配特定关键词的文档,无论是站内新闻、数据库记录还是自建的搜索引擎。 2. lucene 的工作原理 - 写入流程:数据首先通过analyzer进行处理,将原始文本转化为一系列...
每个文档对应数据库中的一条记录,包含需要搜索的关键字段。 3. **配置索引目录**:选择一个合适的文件夹作为Lucene的索引存储位置,可以是项目目录下的某个文件夹,也可以是服务器上的特定路径。 4. **定义索引...
通过这种方式,可以在索引文档中查找符合特定模式的记录。 #### 示例代码解析 1. **索引创建**: ```java IndexWriter writer = new IndexWriter(path, new StandardAnalyzer(), true); writer.setUseCompoundFile...
通过将数据库记录映射为 Lucene 的 Document,可以在不离开数据库环境的情况下实现全文检索。例如,可以使用 JDBC 连接数据库,读取记录并转换为 Document,然后进行索引。 ### 4. 实例应用 在实际项目中,我们...
2. **创建Lucene Document**:每个数据库记录对应一个Lucene Document对象,其中包含字段(Field)和值。例如,可以创建一个“title”字段用于存储数据库记录的标题,一个“content”字段用于存储正文内容。 3. **...
术语是索引的基本单元,每个术语对应倒排索引中的一个条目,记录了该术语在哪些文档中出现以及位置信息。 在索引构建阶段,Lucene 1.4.3会读取文档内容,分析出所有术语,并生成倒排索引。这个过程包括分词...
- **文档(Document)**:是Lucene处理的基本单位,通常代表数据库中的一条记录或者一个网页。文档包含一系列字段(Field),每个字段都有一个名字和对应的值。 - **字段(Field)**:字段是文档的组成部分,如标题...
FieldCache用于快速获取文档中的字段值,TermVector记录了词汇项在文档中的位置和频率,postings format则是Lucene内部存储和检索词汇项的具体方式。通过这些高级特性,用户可以深入探究Lucene的底层实现。 总之,...
以下是关于Lucene Field的一些关键知识点: 1. **Field类型**:Lucene中的Field有多种类型,如TextField、StringField、NumericField等。TextField适合全文检索,StringField则用于存储不可变的非全文数据,...
1. 文档(Document):在Lucene中,文档是信息的基本单位,可以理解为数据库中的记录。一个文档包含多个字段(Field),每个字段都有自己的名称和值,如标题、内容、作者等。 2. 字段(Field):字段是文档的组成...
接下来,你需要创建一个索引器类,该类使用Spring的ApplicationContext获取必要的bean,并负责将数据源中的内容(例如数据库中的记录)转换为Lucene的Document对象。Document对象是Lucene索引的基本单位,可以包含多...
- `org.apache.lucene.util`: 提供一些通用工具类和辅助功能。 2. **Lucene的主要逻辑** Lucene的主要逻辑可以分为两个核心部分:索引和查询。 - **索引逻辑**:首先,内容通过语言分析器进行预处理,然后将...
Lucene采用倒排索引(Inverted Index)结构,为每个唯一的术语建立一个术语表,记录该术语在哪些文档中出现以及出现的位置信息,以加速查询速度。 2.3 索引优化 在4.10.3版本中,Lucene对索引过程进行了优化,包括...