lucene
来源:互联网 发布:java培训推荐 编辑:程序博客网 时间:2024/06/15 18:22
demo http://blog.csdn.net/u013573133/article/details/48246351
1. 建立索引
为了简单起见,我们下面为一些字符串创建内存索引:
StandardAnalyzer analyzer = newStandardAnalyzer(Version.LUCENE_40);Directory index = newRAMDirectory(); IndexWriterConfig config = newIndexWriterConfig(Version.LUCENE_40, analyzer); IndexWriter w = newIndexWriter(index, config);addDoc(w,"Lucene in Action","193398817");addDoc(w,"Lucene for Dummies","55320055Z");addDoc(w,"Managing Gigabytes","55063554A");addDoc(w,"The Art of Computer Science","9900333X");w.close();
addDoc()方法把文档(译者注:这里的文档是Lucene中的Document类的实例)添加到索引中。
private static void addDoc(IndexWriter w, String title, String isbn) throws IOException { Document doc = newDocument(); doc.add(newTextField("title", title, Field.Store.YES)); doc.add(newStringField("isbn", isbn, Field.Store.YES)); w.addDocument(doc);}
注意,对于需要分词的内容我们使用TextField,对于像id这样不需要分词的内容我们使用StringField。
2.搜索请求
我们从标准输入(stdin)中读入搜索请求,然后对它进行解析,最后创建一个Lucene中的Query对象.
3.搜索
我们创建一个Searcher对象并且使用上面创建的Query对象来进行搜索,匹配到的前10个结果封装在TopScoreDocCollector对象里返回。
4.展示
现在我们得到了搜索结果,我们需要想用户展示它。
这里是这个小应用的完整代码。下载HelloLucene.java。
public class HelloLucene { public static void main(String[] args) throws IOException, ParseException { // 0. Specify the analyzer for tokenizing text. // The same analyzer should be used for indexing and searching StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_40); // 1. create the index Directory index = newRAMDirectory(); IndexWriterConfig config = newIndexWriterConfig(Version.LUCENE_40, analyzer); IndexWriter w = newIndexWriter(index, config); addDoc(w,"Lucene in Action","193398817"); addDoc(w,"Lucene for Dummies","55320055Z"); addDoc(w,"Managing Gigabytes","55063554A"); addDoc(w,"The Art of Computer Science","9900333X"); w.close(); // 2. query String querystr = args.length > 0? args[0] : "lucene"; // the "title" arg specifies the default field to use // when no field is explicitly specified in the query. Query q = newQueryParser(Version.LUCENE_40,"title", analyzer).parse(querystr); // 3. search inthitsPerPage = 10; IndexReader reader = DirectoryReader.open(index); IndexSearcher searcher = newIndexSearcher(reader); TopScoreDocCollector collector = TopScoreDocCollector.create(hitsPerPage, true); searcher.search(q, collector); ScoreDoc[] hits = collector.topDocs().scoreDocs; // 4. display results System.out.println("Found " + hits.length + " hits."); for(int i=0; i
一、环境
需要导入lucene.jar包(在lucene.apache.org下载)
二、基本概念
1.Lucene的工作流程:
(1) 使用IndexWriter,在指定的目录建立索引的文件
(2)将需要检索的数据转换位Document的Filed对象,然后将Document用IndexWriter添加倒索引的文件中
2.Lucene的字段类型
Lucene有四种不同的字段类型:Keyword,UnIndexed,UnStored和Text,用于指定建立最佳索引。
(1)Keyword字段是指不需要分析器解析但需要被编入索引并保存到索引中的部分。JavaSourceCodeIndexer类使用该字段来保存导入类的声明。
(2)UnIndexed字段是既不被分析也不被索引,但是要被逐字逐句的将其值保存到索引中。由于我们一般要存储文件的位置但又很少用文件名作为关键字来搜索,所以用该字段来索引Java文件名。
(3)UnStored字段和UnIndexed字段相反。该类型的Field要被分析并编入索引,但其值不会被保存到索引中。由于存储方法的全部源代码需要大量的空间。所以用UnStored字段来存储被索引的方法源代码。可以直接从Java源文件中取出方法的源代码,这样作可以控制我们的索引的大小。
(4)Text字段在索引过程中是要被分析、索引并保存的。类名是作为Text字段来保存。下表展示了JavaSourceCodeIndexer类使用Field字段的一般情况。
3.基本概念(与传统表的对比)
Lucene概念
传统概念
备注
IndexWriter
table
Document
一条记录
Field
每个字段
分为可被索引的,可切分的,不可被切分的,不可被索引的几种组合类型
Hits
RecoreSet
结果集
IndexWriter提供了一些参数可供设置,列表如下:
(1).mergeFactory:
(2).maxMergeDocs:限制一个段中的document数目,默认值:Integer.MAX_VALUE
(3).minMergeDocs:缓存在内存中的document数目,超过他以后会写入到磁盘,默认值:10
(4).maxFieldLength:一个Field中最大Term数目,超过部分忽略,不会index到field中,所以自然也就搜索不到,默认值:1000
这些参数的的详细说明比较复杂:mergeFactor有双重作用
(1)设置每mergeFactor个document写入一个段,比如每10个document写入一个段
(2)设置每mergeFacotr个小段合并到一个大段,比如10个document的时候合并为1小段,以后有10个小段以后合并到一个大段,有10个大段以后再合并,实际的document数目会是mergeFactor的指数
简单的来说mergeFactor越大,系统会用更多的内存,更少磁盘处理,如果要打批量的作index,那么把mergeFactor设置大没错, mergeFactor小了以后,index数目也会增多,searhing的效率会降低,但是mergeFactor增大一点一点,内存消耗会增大很多(指数关系),所以要留意不要”outof memory”
把maxMergeDocs设置小,可以强制让达到一定数量的document写为一个段,这样可以抵消部分mergeFactor的作用.
minMergeDocs相当于设置一个小的cache,第一个这个数目的document会留在内存里面,不写入磁盘。这些参数同样是没有最佳值的,必须根据实际情况一点点调整。
maxFieldLength可以在任何时刻设置,设置后,接下来的index的Field会按照新的length截取,之前已经index的部分不会改变。可以设置为Integer.MAX_VALUE
4.几种查询方式
查询方式
说明
TermQuery
条件查询
例如:TermQuery tquery=new TermQuery(new Term("name","jerry"));
name:字段名
jerry:要搜索的字符串
MultiTermQuery
多个字段进行同一关键字的查询
Query query= null;
Query =MultiFieldQueryParser.parse("我",newString[]
Searcher searcher=new IndexSearcher(indexFilePath);
Hits hits=searcher.search(query);
BooleanQuery
例如:BooleanQuery bquery=new BooleanQuery();
WildcardQuery
语义查询(通配符查询)
例:Query query= new WildcardQuery(new Term("sender","*davy*"));
PhraseQuery
短语查询
PrefixQuery
前缀查询
PhrasePrefixQuery
短语前缀查询
FuzzyQuery
模糊查询
RangeQuery
范围查询
SpanQuery
范围查询
在全文检索时建议大家先采用语义时的搜索,先搜索出有意义的内容,之后再进行模糊之类的搜索
(1)联合两个索引查询,已解决:
IndexSearcher[] searchers = new IndexSearcher[2]; searchers[0] = new IndexSearcher(m_indexpath); searchers[1] = new IndexSearcher(m_outindexpath); MultiSearcher multiSearcher = new MultiSearcher(searchers);v
(2)还有个进行多条件搜索 and 与 or 的操作————
用 MultiFieldQueryParser
建议重新封装
MultiFieldQueryParser.Parser(p[],d[],f[],analyer)
或者
BooleanQuery m_BooleanQuery = new BooleanQuery();
Query query = QueryParser.Parse(m_SearchText, "INSTRUMENT_NAME",analyzer);
Query query2 = QueryParser.Parse(m_SearchText2, "INSTRUMENT_NAME2",analyzer);
m_BooleanQuery.Add(query, true, false);
m_BooleanQuery.Add(query2, true, false);
(3)复合查询(多种查询条件的综合查询)
Query query=MultiFieldQueryParser.parse("索引”,newString[]
Searcher searcher=new IndexSearcher(indexFilePath);
Hits hits=searcher.search(query);
for (int i = 0; i < hits.length();i++)
}
5.为查询优化索引(index)
Indexwriter.optimize()方法可以为查询优化索引(index),之前提到的参数调优是为indexing过程本身优化,而这里是为查询优化,优化主要是减少index文件数,这样让查询的时候少打开文件,优化过程中,lucene会拷贝旧的index再合并,合并完成以后删除旧的index,所以在此期间,磁盘占用增加,IO符合也会增加,在优化完成瞬间,磁盘占用会是优化前的2倍,在optimize过程中可以同时作search。
4.org.apache.lucene.document.Field
类型
Analyzed
Indexed
Stored
说明
Field.Keyword(String,String/Date)
N
Y
Y
这个Field用来储存会直接用来检索的比如(编号,姓名,日期等)
Field.UnIndexed(String,String)
N
N
Y
不会用来检索的信息,但是检索后需要显示的,比如,硬件序列号,文档的url地址
Field.UnStored(String,String)
Y
Y
N
大段文本内容,会用来检索,但是检索后不需要从index中取内容,可以根据url去load真实的内容
Field.Text(String,String)
Y
Y
Y
5.Lucene 的检索结果排序
Sort sort = new Sort("id");
Hits hits = searcher.search(query, sort);
用户还可以根据自己定义更加复杂的排序,详细请参考
6.分词器(分析器)
Lucene使用分析器来处理被索引的文本。在将其存入索引之前,分析器用于将文本标记化、摘录有关的单词、丢弃共有的单词、处理派生词(把派生词还原到词根形式,意思是把bowling、bowler和bowls还原为bowl)和完成其它要做的处理。Lucene提供的通用分析器是:
十、需要注意的问题:
1.IndexWriter在添加新的document后,需要重新建立Index,则需要调用writer.optimize();方法
2. Lucene没有update索引的方法,需要删除后重新建立,参考remove方法
3.用IndexReader删除Document后,需要重新用IndexWriter进行整理,否则无法在进行搜索(不知道是不是我设置问题)
4.Lucene先在内存中进行索引操作,并根据一定的批量进行文件的写入。这个批次的间隔越大,文件的写入次数越少,但占用内存会很多。反之占用内存少,但文件IO操作频繁,索引速度会很慢。在IndexWriter中有一个MERGE_FACTOR参数可以帮助你在构造索引器后根据应用环境的情况充分利用内存减少文件的操作。根据我的使用经验:缺省Indexer是每20条记录索引后写入一次,每将MERGE_FACTOR增加50倍,索引速度可以提高1倍左右。
5.并发操作Lucene
(1)所有只读操作都可以并发
(2)在index被修改期间,所有只读操作都可以并发
(3)对index修改操作不能并发,一个index只能被一个线程占用
(4)ndex的优化,合并,添加都是修改操作
(5)但需要注意的是,在创建搜索的时候用:
searcher = newIndexSearcher(IndexReader.open("E:\\lucene\\test4\\index"));
searcher.close();
这时候是不能关闭searcher的.
如果想让searcher能关闭,就不要用IndexReader了:
6.Locking机制
lucence内部使用文件来locking,默认的locking文件放在java.io.tmpdir,可以通过-Dorg.apache.lucene.lockDir=xxx指定新的dir,有write.lockcommit.lock两个文件,lock文件用来防止并行操作index,如果并行操作,lucene会抛出异常,可以通过设置-DdisableLuceneLocks=true来禁止locking,这样做一般来说很危险,除非你有操作系统或者物理级别的只读保证,比如把index文件刻盘到CDROM上。
十一、2.0中新增特性
1.新增类: org.apache.lucene.index.IndexModifier,它合并了
2.增加对 contrib/highlighter 的 NullFragmenter , 这对全文本加亮很有用。
3.增加了新类 MatchAllDocsQuery 用来匹配所有文档。
4.. 增加 ParallelReader,这个一种IndexReader 他合并多个单独的索引到一个单独的虚拟索引上。
5.增加 Hits.iterator() 方法和相应的 HitIterator 和 Hit 对象。
他提供了对 Hits对象标准的 java.util.Iterator 叠代操作。
每个iterator's next() 方法返回一个 Hit 对象。
6. 在 term vectors 中增加了位置和偏移信息。(Grant Ingersoll & Christoph)
7. 增加了一个新的 DateTools 。允许用户格式化日期到一种更可读的格式,以便于更好的适应索引。
8. 增加了对压缩字段存储的支持。
实例:
1.判断索引文件是否存在:
public static boolean indexExist(String indexDir){ return IndexReader.indexExists(indexDir); } private IndexWriter getWriter(String indexFilePath) throws Exception { boolean append=true; File file=new File(indexFilePath+File.separator+"segments"); if(file.exists()) append=false; return new IndexWriter(indexFilePath,analyzer,append); }
2.删除索引
public static void deleteIndex(Term aTerm, String indexDir) { List aList = new ArrayList(); aList.add(aTerm); deleteIndex(aList, indexDir); } public static void deleteIndex(List terms, String indexDir) { if (null == terms) { return; } if(!indexExist(indexDir)) { return; } IndexReader reader = null; try { reader = IndexReader.open(indexDir); for (int i = 0; i < terms.size(); i++){ Term aTerm = (Term) terms.get(i); if (null != aTerm){ reader.delete(aTerm); } } } catch (IOException e){ LogMan.warn("Error in Delete Index", e); } finally { try{ if (null != reader){ reader.close(); } }catch (IOException e){ LogMan.warn("Close reader Error"); } } }
删除索引需要一个条件,类似数据库中的字段条件,例如删除一条新闻的代码如下:
public static void deleteNewsInfoIndex(int nid){ Term aTerm = new Term("nid", String.valueOf(nid)); deleteIndex(aTerm,indexDir); } public class LuceneSearch {public static void main(String[] args) throws Exception{ LuceneSearch test = new LuceneSearch(); Hits h = null; h = test.search("显示 "); test.printResult(h); h = test.search("jy"); test.printResult(h); h = test.search("djy"); test.printResult(h); h = test.search("料不"); test.printResult(h); h = test.search("人"); test.printResult(h);}public LuceneSearch(){ try{ searcher = new IndexSearcher(IndexReader.open("E:\\lucene\\test4\\index")); }catch(Exception e){ e.printStackTrace(); }}//声明一个IndexSearcher对象private IndexSearcher searcher = null;//声明一个Query对象private Query query = null;ChineseAnalyzer analyzer = new ChineseAnalyzer();Highlighter highlighter = null;public final Hits search(String keyword){ System.out.println("正在检索关键字:"+keyword); try{ Date start = new Date(); QueryParser qp = new QueryParser("content",analyzer); query = qp.parse(keyword);// Hits hits = searcher.search(query); // Term term = new Term("content",keyword);// FuzzyQuery fq = new FuzzyQuery(term);// Hits hits = searcher.search(fq); // BooleanClause.Occur[] flags = new BooleanClause.Occur[]{BooleanClause.Occur.SHOULD,BooleanClause.Occur.MUST};// query=MultiFieldQueryParser.parse(keyword,new String[]{"title","content"},flags,analyzer); // query=MultiFieldQueryParser.parse(new String[]{keyword,keyword},new String[]{"title","content"},analyzer); // BooleanClause.Occur[] flags = new BooleanClause.Occur[]{BooleanClause.Occur.MUST_NOT,BooleanClause.Occur.MUST};// query=MultiFieldQueryParser.parse(new String[]{keyword,keyword},new String[]{"title","content"},flags,analyzer); // Term lowerTerm1 = new Term("id","53");// Term upperTerm1 = new Term("id","55");// RangeQuery rq1 = new RangeQuery(lowerTerm1,upperTerm1,true);// // Term lowerTerm2 = new Term("id","57");// Term upperTerm2 = new Term("id","60");// RangeQuery rq2 = new RangeQuery(lowerTerm2,upperTerm2,true);// // BooleanQuery bq = new BooleanQuery();// bq.add(rq1,BooleanClause.Occur.SHOULD);// bq.add(rq2,BooleanClause.Occur.SHOULD); //手工拼范围// query = QueryParser.Parse("{200004 TO 200206}", "pubmonth", new SimpleAnalyzer());// Lucene用[] 和{}分别表示包含和不包含. //String temp = "startDate:["+nextWeek[0]+" TO "+nextWeek[1]+"] "; // temp = temp + " OR endDate:["+nextWeek[0]+" TO "+nextWeek[1]+"]"; // Query query1 = qp.parse(temp); // Hits hits = searcher.search(bq); // Sort sort = new Sort(new SortField[]{new SortField("id", SortField.INT, true)});// Hits hits = searcher.search(query,sort); // Sort sort = new Sort(new SortField[]{new SortField("createTime", SortField.INT, false)}); // QueryParser qp1 = new QueryParser("content",analyzer);// Query fquery = qp1.parse("我");// // BooleanQuery bqf = new BooleanQuery();// bqf.add(fquery,BooleanClause.Occur.SHOULD);// // QueryFilter qf = new QueryFilter(bqf); Hits hits = searcher.search(query); Date end = new Date(); System.out.println("检索完成,用时"+(end.getTime()-start.getTime())+"毫秒"); return hits; }catch(Exception e){ e.printStackTrace(); return null; } }public void printResult(Hits h){ if(h.length() == 0){ System.out.println("对不起,没有找到您要的结果."); }else{ for(int i = 0; i < h.length(); i++){ try{ Document doc = h.doc(i); System.out.println("结果"+(i+1)+":"+doc.get("id")+" createTime:"+doc.get("createTime")+" title:"+doc.get("title")+" content:"+doc.get("content")); //System.out.println(doc.get("path")); }catch(Exception e){ e.printStackTrace(); } } } System.out.println("--------------------------------------");}}
- lucene
- Lucene
- lucene
- lucene
- Lucene
- lucene
- lucene
- lucene
- Lucene
- Lucene
- lucene
- Lucene
- Lucene
- Lucene
- lucene
- lucene
- Lucene
- Lucene
- redis主从复制
- 文章标题
- MatLab分类器大全(svm,knn,…
- Memcached分布式布置方案--一致性H…
- 全文检索框架Lucene——Demo应用
- lucene
- python读取存储matlab的 .mat文件
- 分布式ID生成策略
- Java导出Highcharts生成的图表为图片源码
- Restful API Design
- Fine Uploader文件上传组件
- New Relic:不等应用崩溃,实时监…
- 线程池参数说明及队列拒绝策略
- WebService到底是什么?