lucene、lucene.NETの詳細な使用と最適化の詳細

99962 ワード

lucene、lucene.NETの詳細な使用と最適化の詳細
1 luceneの概要
1.1 lucene Luceneとは、アプリケーションではなく全文検索フレームワークです.www.baiduとは違いますcomやgoogle Desktopは、これらの製品を実現するためのツールを提供しているだけです.
1.2 luceneが何ができるかこの質問に答えるには、まずluceneの本質を理解しなければならない.実際にluceneの機能は単一で、結局、あなたはそれにいくつかの文字列をあげて、それからそれはあなたに全文検索サービスを提供して、あなたが検索するキーワードがどこに現れるかを教えます.この本質を知れば、この条件に合ったことを想像することができます.駅のニュースをインデックスして、リポジトリを作ることができます.データベース・テーブルのいくつかのフィールドをインデックスできます.「%like%」のためにテーブルをロックする心配はありません.自分の検索エンジンを書くこともできますが...
1.3 luceneの下にいくつかのテストデータを与えるべきではありません.もしあなたが受け入れることができると思ったら、選択することができます.
テスト1:250万記録、300 M程度のテキスト、インデックス380 M程度を生成し、800スレッドで平均処理時間300 ms.
テスト2:37000レコード、インデックスデータベースの2つのvarcharフィールド、インデックスファイル2.6 M、800スレッドでの平均処理時間1.5 ms.
2 luceneの働き方luceneが提供するサービスには、実際には2つの部分が含まれています.入力とは書き込みであり、あなたが提供したソース(本質は文字列)をインデックスに書き込むか、インデックスから削除します.読み出しとは、ユーザーに全文検索サービスを提供し、ユーザーがキーワードを通じてソースを特定できるようにします.
2.1プロセスソース文字列を書き込むには、まずanalyzer処理を経て、分詞を含み、1つの単語に分ける.stopwordを除去します(オプション).
ソースに必要な情報をDocumentの各Fieldに加え,インデックスが必要なFieldをインデックスし,格納するFieldを格納する.
インデックスをメモリに書き込みます.メモリはメモリまたはディスクです.
2.2読み出しプロセスユーザは検索キーワードを提供し、analyzer処理を経た.
処理後のキーワード検索インデックスに対して対応するDocumentを探し出す.
ユーザは,必要に応じて見つけたDocumentから必要なFieldを抽出する.
3知っておくべき概念luceneはいくつかの概念を使って、それらの意味を理解して、以下の説明に役立ちます.
3.1 analyzer Analyzerは分析器であり、その役割は一つの文字列をある規則によって一つの語に分け、その中の無効な語を取り除くことである.ここで言う無効な語は英語の「of」、「the」、中国語の「の」、「地」などの語を指し、これらの語は文章の中で大量に現れているが、それ自体には重要な情報は含まれていない.インデックスファイルの縮小、効率の向上、ヒット率の向上に役立ちます.
分詞の規則は千変万化しているが、目的は一つしかない.意味によって区分されている.この点は英語では実現しやすい.英語自体が単語単位で、スペースで分かれているからだ.中国語は一つにつながった文を一つの言葉に分ける方法が必要だ.具体的な区分方法は以下に詳しく紹介しますが、ここではアナライザの概念を知るだけでいいです.
3.2 documentユーザーが提供するソースは、テキストファイル、文字列、またはデータベース・テーブルのレコードなどであることができるレコードです.1つのレコードがインデックスを通過すると、インデックスファイルにDocumentとして格納されます.ユーザによる検索もDocumentリストとして返される.
3.3 field 1つのDocumentは、複数の情報ドメインを含むことができ、例えば、1つの文章には、FieldによってDocumentに格納される「タイトル」、「本文」、「最終変更時間」などの情報ドメインを含むことができる.
Fieldには、ストレージとインデックスの2つのプロパティがあります.属性を保存することで、このFieldを保存するかどうかを制御できます.インデックス属性を使用すると、Fieldをインデックスするかどうかを制御できます.これはくだらない話のように見えますが、実際にはこの2つの属性の正確な組み合わせが重要です.次に例を挙げて説明します.
やはり先ほどの文章を例にとると、タイトルと本文を全文検索する必要があるので、インデックス属性を真に設定するとともに、検索結果から直接文章タイトルを抽出したいので、タイトルドメインのストレージ属性を真に設定しますが、本文ドメインが大きすぎるため、インデックスファイルのサイズを縮小するために、本文ドメインのストレージ属性を偽に設定し、必要に応じてファイルを直接読み出す.検索結果から最後の変更時間を抽出したいだけで、検索する必要はありません.そのため、最後の変更時間ドメインのストレージ属性を真に設定し、インデックス属性を偽に設定します.上の3つのドメインは2つの属性の3つの組み合わせをカバーしており、1つはすべて偽物で使用されていません.実際にはFieldは、インデックスを格納しないドメインには意味がないため、設定を許可していません.
3.4 term termは検索の最小単位であり、ドキュメントの1つの語を表し、termは2つの部分から構成されている:それが表す語とこの語が現れるfield.
3.5 tocken tockenはtermの出現であり、tremテキストと対応する立ち上がりオフセット、およびタイプ文字列を含む.1つの文には同じ言葉が何度も現れ、同じtermで表されるが、異なるtockenで、各tockenがその言葉が現れた場所をマークする.
3.6 segment
インデックスを追加すると、各documentがすぐに同じインデックスファイルに追加されるわけではありません.まず、異なる小さなファイルに書き込まれ、次に大きなインデックスファイルにマージされます.ここで、各小さなファイルはsegmentです.
4 luceneの構造luceneはcoreとsandboxの2つの部分を含み、coreはluceneの安定したコア部分であり、sandboxはhighlighter、各種分析器などの追加機能を含む.
Lucene coreには、analysis、document、index、queryParser、search、store、utilの7つのパッケージがあります.
4.1 analysis Analysisには、空白文字で区切られたWhitespaceAnalyzer、stopwrodフィルタが追加されたStopAnalyzer、最も一般的なStandardAnalyzerなど、いくつかの組み込まれたアナライザが含まれています.
4.2 document Documentには、ドキュメントのデータ構造が含まれます.たとえば、Documentクラスはドキュメントを格納するデータ構造を定義し、FieldクラスはDocumentのドメインを定義します.
4.3 index Indexには、インデックスファイルのsegmentの書き込み、マージ、最適化されたIndexWriterクラス、インデックスの読み取りと削除操作を行うIndexReaderクラスなど、インデックスの読み書きクラスが含まれています.ここで注意したいのは、IndexReaderという名前に誤解されないように、インデックスファイルの読み取りクラスだと思って、実際にインデックスの削除もそれによって行われます.IndexWriterは、インデックスを個々のsegmentに書き込む方法にのみ関心を持ち、それらを統合して最適化します.IndexReaderは、インデックスファイル内の各ドキュメントの組織形式に注目します.
4.4 queryParser QueryParserは解析クエリ文のクラスを含み、luceneのクエリ文はsql文と少し似ていて、各種の予約字があり、一定の文法によって各種のクエリを構成することができる.Luceneには多くのQueryクラスがあり、それらはすべてQueryから継承され、各種の特殊なクエリーを実行し、Query Parserの役割はクエリー文を解析し、各種Queryクラスを順番に呼び出して結果を探し出すことである.
4.5 search Searchはインデックスから検索結果を含む様々なクラス、例えば先ほどお話ししたような様々なQueryクラス、TermQuery、BooleanQueryなどがこのパッケージに含まれています.
4.6 store
Storeはインデックスの格納クラスを含み、例えばDirectoryはインデックスファイルの格納構造を定義し、FSDirectoryはファイルに格納されたインデックスであり、RAM Directoryはメモリに格納されたインデックスであり、MmapDirectoryはメモリマッピングを用いたインデックスである.
4.7 util Utilには、時間と文字列間の変換ツールなどの共通のツールクラスが含まれています.
5インデックスの作成方法
5.1最も簡単なインデックスを作成できるコード

   
   
   
   
  1. IndexWriter writer = new IndexWriter(“/data/index/”, new StandardAnalyzer(), true);
  2. Document doc = new Document();
  3. doc. add( new Field( "title", "lucene introduction", Field.Store.YES, Field.Index.TOKENIZED));
  4. doc. add( new Field( "content", "lucene works well", Field.Store.YES, Field.Index.TOKENIZED));
  5. writer.addDocument(doc);
  6. writer.optimize();
  7. writer.close();



writer, “/data/index”, StandardAnalyzer, , 。
document。
document field, “title”, “lucene introduction”, 。
“content” field, “lucene works well”, 。
, , , document 。
document, , segment , 。
writer , 。

, !


5.2

RAMDirectory, writer, :


   
   
   
   
  1. Directory dir = new RAMDirectory();
  2. IndexWriter writer = new IndexWriter(dir, new StandardAnalyzer(), true);
  3. Document doc = new Document();
  4. doc. add( new Field( "title", "lucene introduction", Field.Store.YES, Field.Index.TOKENIZED));
  5. doc. add( new Field( "content", "lucene works well", Field.Store.YES, Field.Index.TOKENIZED));
  6. writer.addDocument(doc);
  7. writer.optimize();
  8. writer.close();

5.3

, field, field:

Field field = new Field("content", new FileReader(file));

file 。 , , 。

6

IndexReader 。

6.1

lucene document ,

void deleteDocument(int docNum)

document , document , , , , 。

void deleteDocuments(Term term)

term , 。 , document 。



   
   
   
   
  1. Directory dir = FSDirectory.getDirectory(PATH, false);
  2. IndexReader reader = IndexReader.open(dir);
  3. Term term = new Term(field, key);
  4. reader.deleteDocuments(term);
  5. reader.close();

6.2

lucene , document , document 。 :


   
   
   
   
  1. Directory dir = FSDirectory.getDirectory(PATH, false);
  2. IndexReader reader = IndexReader.open(dir);
  3. Term term = new Term(“title”, “lucene introduction”);
  4. reader.deleteDocuments(term);
  5. reader.close();
  6. IndexWriter writer = new IndexWriter(dir, new StandardAnalyzer(), true);
  7. Document doc = new Document();
  8. doc. add( new Field( "title", "lucene introduction", Field.Store.YES, Field.Index.TOKENIZED));
  9. doc. add( new Field( "content", "lucene is funny", Field.Store.YES, Field.Index.TOKENIZED));
  10. writer.addDocument(doc);
  11. writer.optimize();
  12. writer.close();

7

lucene , , Query , , , ; lucene Sort , Filter 。 SQL :“lucene and、or、order by、where、like ‘%xx%’ ?” :“ !”

7.1 Query

lucene :

7.1.1 TermQuery
, :“ content ‘lucene’ document”, TermQuery:


   
   
   
   
  1. Term t = new Term( "content", " lucene";
  2. Query query = new TermQuery(t);



7.1.2 BooleanQuery
:“ content java perl document”, TermQuery BooleanQuery :


   
   
   
   
  1. TermQuery termQuery1 = new TermQuery( new Term( "content", "java");
  2. TermQuery termQuery 2 = new TermQuery( new Term( "content", "perl");
  3. BooleanQuery booleanQuery = new BooleanQuery();
  4. booleanQuery. add(termQuery 1, BooleanClause.Occur.SHOULD);
  5. booleanQuery. add(termQuery 2, BooleanClause.Occur.SHOULD);


7.1.3 WildcardQuery
, WildcardQuery, ’?’ ’*’ , ’use*’, ’useful’ ’useless’:

Query query = new WildcardQuery(new Term("content", "use*");
   
   
   
   

7.1.4 PhraseQuery
, ‘ ’ ‘ ’ (5 ) , , :


   
   
   
   
  1. PhraseQuery query = new PhraseQuery();
  2. query.setSlop( 5);
  3. query. add( new Term( "content ", “ ”));
  4. query. add( new Term(“content”, “ ”));

“ ……”、“ ……”, “ ”。

7.1.5 PrefixQuery
‘ ’ , PrefixQuery:

PrefixQuery query = new PrefixQuery(new Term("content ", " ");
   
   
   
   



7.1.6 FuzzyQuery
FuzzyQuery term, Levenshtein 。 ‘wuzza’ , :

Query query = new FuzzyQuery(new Term("content", "wuzza");
   
   
   
   


‘fuzzy’ ‘wuzzy’。

7.1.7 RangeQuery
Query RangeQuery, 20060101 20060130 document, RangeQuery:

RangeQuery query = new RangeQuery(new Term(“time”, “20060101”), new Term(“time”, “20060130”), true);
   
   
   
   


true 。

7.2 QueryParser

Query, :“ Query , !” ,lucene SQL , lucene , , ,lucene Query 。 Query :
TermQuery “field:key” , “content:lucene”。
BooleanQuery ‘ ’ ‘+’,‘ ’ ‘ ’, “content:java contenterl”。
WildcardQuery ‘?’ ‘*’, “content:use*”。
PhraseQuery ‘~’, “content:" "~5”。
PrefixQuery ‘*’, “ *”。
FuzzyQuery ‘~’, “content: wuzza ~”。
RangeQuery ‘[]’ ‘{}’, , , “time:[20060101 TO 20060130]”, TO 。
query string, , “ lucene, 20060101 20060130 ” :“+ (title:lucene content:lucene) +time:[20060101 TO 20060130]”。 :


   
   
   
   
  1. Directory dir = FSDirectory.getDirectory(PATH, false);
  2. IndexSearcher is = new IndexSearcher(dir);
  3. QueryParser parser = new QueryParser( "content", new StandardAnalyzer());
  4. Query query = parser.parse( "+(title:lucene content:lucene) +time:[20060101 TO 20060130]";
  5. Hits hits = is.search(query);
  6. for ( int i = 0; i < hits.length(); i++)
  7. {
  8. Document doc = hits.doc(i);
  9. System. out.println(doc. get( "title");
  10. }
  11. is.close();


IndexSearcher。
StandardAnalyzer QueryParser, content。
QueryParser parse , Query。
Query , Hits 。
Hits , 。

7.3 Filter

filter , SQL where, , , , 。 , , filter , 。
filter RangeFilter QueryFilter。RangeFilter ;QueryFilter 。
Filter , filter , searcher。 , “ 20060101 20060130 ” query string , RangeFilter :


   
   
   
   
  1. Directory dir = FSDirectory.getDirectory(PATH, false);
  2. IndexSearcher is = new IndexSearcher(dir);
  3. QueryParser parser = new QueryParser( "content", new StandardAnalyzer());
  4. Query query = parser.parse( "title:lucene content:lucene";
  5. RangeFilter filter = new RangeFilter( "time", "20060101", "20060230", true, true);
  6. Hits hits = is.search(query, filter);
  7. for ( int i i < hits.length(); i++)
  8. {
  9. Document doc = hits.doc(i);
  10. System. out.println(doc. get( "title");
  11. }
  12. is.close();


, 2005-10-1 2005-10-30 。
, , 。


   
   
   
   
  1. // index
  2. document.Add(FieldDate, DateField.DateToString(date), Field.Store.YES, Field.Index.UN_TOKENIZED);
  3. //...
  4. // search
  5. Filter filter = new DateFilter(FieldDate, DateTime.Parse( "2005-10-1"), DateTime.Parse( "2005-10-30"));
  6. Hits hits = searcher.Search(query, filter);


, 。 100 ~ 200 。
Lucene.Net NumberTools , 。


   
   
   
   
  1. // index
  2. document.Add( new Field(FieldNumber, NumberTools.LongToString(( long)price), Field.Store.YES, Field.Index.UN_TOKENIZED));
  3. //...
  4. // search
  5. Filter filter = new RangeFilter(FieldNumber, NumberTools.LongToString( 100L), NumberTools.LongToString( 200L), true, true);
  6. Hits hits = searcher.Search(query, filter);


Query 。
QueryFilter filter = new QueryFilter(QueryParser.Parse("name2", FieldValue, analyzer));
   
   
   
   

FilteredQuery 。


   
   
   
   
  1. Filter filter = new DateFilter(FieldDate, DateTime.Parse( "2005-10-10"), DateTime.Parse( "2005-10-15"));
  2. Filter filter2 = new RangeFilter(FieldNumber, NumberTools.LongToString( 11L), NumberTools.LongToString( 13L), true, true);
  3. Query query = QueryParser.Parse( "name*", FieldName, analyzer);
  4. query = new FilteredQuery(query, filter);
  5. query = new FilteredQuery(query, filter2);
  6. IndexSearcher searcher = new IndexSearcher(reader);
  7. Hits hits = searcher.Search(query);

7.4 Sort


, SQL “order by”,lucene : Sort。
Sort sort Sort(“time”); // SQL “order by time”
Sort sort = new Sort(“time”, true); // SQL “order by time desc”



   
   
   
   
  1. Directory dir = FSDirectory.getDirectory(PATH, false);
  2. IndexSearcher is = new IndexSearcher(dir);
  3. QueryParser parser = new QueryParser( "content", new StandardAnalyzer());
  4. Query query = parser.parse( "title:lucene content:lucene";
  5. RangeFilter filter = new RangeFilter( "time", "20060101", "20060230", true, true);
  6. Sort sort = new Sort(“time”);
  7. Hits hits = is.search(query, filter, sort);
  8. for ( int i = 0; i < hits.length(); i++)
  9. {
  10. Document doc = hits.doc(i);
  11. System. out.println(doc. get( "title");
  12. }
  13. is.close();

7.5  


MultiReader MultiSearcher 。


   
   
   
   
  1. MultiReader reader = new MultiReader( new IndexReader[] { IndexReader.Open( @"c:\index"), IndexReader.Open( @"\\server\index") });
  2. IndexSearcher searcher = new IndexSearcher(reader);
  3. Hits hits = searcher.Search(query);
  4. IndexSearcher searcher1 = new IndexSearcher(reader1);
  5. IndexSearcher searcher2 = new IndexSearcher(reader2);
  6. MultiSearcher searcher = new MultiSearcher( new Searchable[] { searcher1, searcher2 });
  7. Hits hits = searcher.Search(query);

ParallelMultiSearcher 。

7.6


, 。


   
   
   
   
  1. BooleanQuery query = new BooleanQuery();
  2. query.Add(query1, true, false);
  3. query.Add(query2, true, false);
  4. //...
  5. Console.WriteLine( "Syntax: {0}", query.ToString());



Syntax: +(name:name* value:name*) +number:[0000000000000000b TO 0000000000000000d]


, 。

8

, 。 : StandardAnalyzer, StandardAnalyzer 。 StandardAnalyzer 。
,StandardAnalyzer ? , , “ ” “ ” , 。 ?core , sandbox : ChineseAnalyzer CJKAnalyzer。 。 StandardAnalyzer ChineseAnalyzer , ,CJKAnalyzer , 。
, 。StandardAnalyzer ChineseAnalyzer , “ ” “ ”; CJKAnalyzer “ ”。 “ ” 。
: 。 “ ”。 , “ ” “ ” ? , , , , , 。 , , , 。 , , , 。
, , 。 , 、 , 。 , ICTCLAS JE-Analysis。ICTCLAS , java , , 。JE-Analysis , , 。= new = 0;


9

, lucene , 。 。 lucene , 。 。 lucene ? 。

9.1

,IndexWriter , RAMDirectory, FSDirectory, , IO, IO。 。

9.1.1 IndexWriter
setMaxBufferedDocs(int maxBufferedDocs)
segment document , , 10。
setMaxMergeDocs(int maxMergeDocs)
segment document , , Integer.MAX_VALUE, 。
setMergeFactor(int mergeFactor)
segment , , 10, 100。

9.1.2 RAMDirectory
RAMDirectory, FSDirectory, IO 。

   
   
   
   
  1. FSDirectory fsDir = FSDirectory.getDirectory( "/data/index", true);
  2. RAMDirectory ramDir = new RAMDirectory();
  3. IndexWriter fsWriter = new IndexWriter(fsDir, new StandardAnalyzer(), true);
  4. IndexWriter ramWriter = new IndexWriter(ramDir, new StandardAnalyzer(), true);
  5. while (there are documents to index)
  6. {
  7. ... create Document ...
  8. ramWriter.addDocument(doc);
  9. if (condition for flushing memory to disk has been met)
  10. {
  11. fsWriter.addIndexes( new Directory[] { ramDir });
  12. ramWriter.close();
  13. ramWriter = new IndexWriter(ramDir, new StandardAnalyzer(), true);
  14. }
  15. }


9.1.3
, , 600M 380M。 , , , cpu, StandardAnalyzer 133 ; MMAnalyzer 150 。

9.2

, , , , 。 , 。 。

9.2.1
, 。Lucene RAMDirectory :


   
   
   
   
  1. Directory fsDir = FSDirectory.getDirectory(“/data/index/”, false);
  2. Directory ramDir = new RAMDirectory(fsDir);
  3. Searcher searcher = new IndexSearcher(ramDir);

RAMDirectory FSDirectory , , ( 400M)RAMDirectory FSDirectory , 。
lucene , 400M , out of memory, 。

9.2.2
, , , ?
, :
1、 RangeQuery, , RangeQuery , BooleanClause BooleanQuery , , , BooleanQuery.TooManyClauses, BooleanQuery.setMaxClauseCount(int maxClauseCount) , , maxClauseCount ,
2、 RangeFilter RangeQuery, RangeQuery , , 90% RangeFilter, RangeFilter , BitSet, document, true, false, Searcher , 。
3、 , :
a、 Filter 。 RangeFilter , , IndexReader, IndexReader Directory , RangeFilter , RangeFilter , RangeFilter , filter BitSet 。 lucene API CachingWrapperFilter Filter , cache CachingWrapperFilter , , CachingWrapperFilter , CachingWrapperFilter , filter , filter IndexReader , IndexReader , , filter IndexReader, 。
b、 。 Filter , , , , , , , , 。
( 800 ):
, :
RangeFilter cache filter
10s 1s 300ms


RangeFilter cache filter
900ms 360ms 300ms



1、 , cache , filter。
2、 , cache 10 。

9.2.3
, 。 。 20% 。


10

10.1

or AND TO ,lucene , 。

10.2



10.3

tmp lock , ,

10.4

lucene yyMMddHHmmss, yy-MM-dd HH:mm:ss lucene

10.5 boost

, , boost , ( )。 :
Field. setBoost(float boost); 1.0, 1 。

1 , ,



   
   
   
   
  1. public static List<string> GetWordsByPanGuAnalyzer(string str)
  2. {
  3. string ret = "";
  4. Analyzer analyzer = new PanGuAnalyzer();
  5. StringReader reader = new StringReader(str);
  6. TokenStream ts = analyzer.TokenStream(str, reader);
  7. bool hasNext = ts.IncrementToken();
  8. ITermAttribute ita;
  9. while (hasNext)
  10. {
  11. ita = ts.GetAttribute();
  12. ret += ita.Term + "|";
  13. hasNext = ts.IncrementToken();
  14. }
  15. ts.CloneAttributes();
  16. reader.Close();
  17. analyzer.Close();
  18. return ret.Split( '|').ToList< string>();
  19. }



2

DictManage.exe PanGu_Release_V2.3.1.0 ,

: http://download.csdn.net/detail/huwei2003/9697994


--- end ---