私が理解しているluceneの原理(初級)


1まず前の段のコード、最も簡単なluceneのHello Worldコードを分析します
 
package cn.itcast.lesson;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.Field.TermVector;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.junit.Test;

public class HelloWorld {
	String title = "IndexWriter.addDocument 's javadoc";
	String content = "Adds  a document to this index. If the document contains more than setMaxFieldLength(int) terms for a given field, the remainder are discarded.";

	String indexPath = "d:/luceneIndex_20100316/"; //          
	Analyzer analyzer = new StandardAnalyzer();    //    

	/**      */
	@Test
	public void createIndex() throws Exception {
		// 1,     Lucene Document
		Document doc = new Document();
		
		Field field = new Field("title", title, Store.YES, Index.ANALYZED);
		Field field2 = new Field("content", content, Store.YES, Index.ANALYZED);
		doc.add(field);
		doc.add(field2);
		/**
		 *       :
		 *      document,   document?        ,document      field   List  。
		 *   list      Filed     。
		 *    Field     Map  ,    name value 。value      (                )。
		 *   Field      public Field(String name, String value, Store store, Index index, TermVector termVector)
		 * Store,  Field       。--- Store.NO,   。 Store.YES,  。Store.COMPRESS,     
		 * Index,  Field        。----Index.NO,   (          )。Index.ANALYZED,     。Index.NOT_ANALYZED,   ,    (   Field     term)。
		 */
		
		
		// 2, Document       
		IndexWriter indexWriter = new IndexWriter(indexPath, analyzer, MaxFieldLength.LIMITED);
		indexWriter.addDocument(doc);
		indexWriter.close();
		
		/**
		 *       :
		 * IndexWriter Lucene             。      IndexWriter(Directory d, Analyzer a, MaxFieldLength mfl); 
		 * Directory,    Lucene          。       ,        ,     FSDirectory,                  。     RAMDirectory,                 。
		 * Analyzer,          ,               ,         Analyzer    。Analyzer        ,      。                  Analyzer。Analyzer          IndexWriter      。
		 * MaxFieldLength,    Field   。                 Field    。     10000,      Field  10000 Term(   )。      Field    10000 Term(   )    ,           Lucene  ,         。
		 */
	}

	/**    */
	@Test
	public void search() throws Exception {
		String queryString = "document";

		IndexSearcher indexSearcher = new IndexSearcher(indexPath);

		QueryParser queryParser = new QueryParser("content", analyzer);
		Query query = queryParser.parse(queryString);
		Filter filter = null;
		int n = 10000;
		/**
		 *      IndexSearcher.search(Query, Filter, int);
		 * Query,    ,              Lucene     Query。
		 * Filter,        。
		 *      (int  ),     Document   。
		 *       TopDocs     ,  TopDocs.scoreDocs      。
		 */
		TopDocs topDocs = indexSearcher.search(query, filter, n); //   
		
		
		

		System.out.println("  【" + topDocs.totalHits + "】     "); //         
		for( ScoreDoc scoreDoc : topDocs.scoreDocs ){
			int docSn = scoreDoc.doc; //        
			Document doc = indexSearcher.doc(docSn); //         
			System.out.println("------------------");
			System.out.println("title   = " + doc.getField("title").stringValue());
			System.out.println("content = " + doc.getField("content").stringValue());
		}
		
		indexSearcher.close();
	}
}

 
 
2 luceneの原理を分析する
 
インデックスファイルの保存形式.インデックスファイルは2つの部分(インデックス領域とデータ領域)に分かれています.
 
 
 
インデックス領域
インデックス領域に格納されているキーワードは、キーワードとどのタイプのキーワードですか.また、このキーワードに対応するデータ領域の内容の符号を格納する.(逆インデックス)
データ領域
データ領域に保存されているのはDocumentで、docuemntの中にはfiledが入っています.Filedはmapと理解でき、中のデータはStringタイプです.
 
インデックスの作成を開始すると、luceneはコンテンツを分詞し、分詞によって生成されたキーワードをインデックス領域に格納し、キーワードがneteaseタイプtitleのインデックス「netease-title」のようなキーワードのタイプをマークし、一連の引用符を保持してデータ領域のfieldを指す.もちろん、これらのfiledにはインデックスの内容もあります.これが「逆インデックス」です
検索に入ると、キーワードを入力した後、luceneは入力したキーワードを分析し、対応するキーワードを生成し、インデックス領域に行って検索し、一致する情報が見つかったら、インデックス領域に保存されているインデックス番号に従ってdocumentのfieldを見つけ、この値をviewレイヤに返します.
 
3 luceneヘルプ
 
***1,Directory,a)FSDirectory,インデックスをディスクに格納する2つあります.b)RAM Directory、インデックスをメモリに入れる.速度は速いが、jvmが終了するとメモリ内のインデックスは存在しない.jvmが終了する前に、FSDirectoryを使用するIndexWriterを呼び出してメモリ内のインデックスをファイルシステムに転送できます.対応するAPIはIndexWriterである.addIndexesNoOptimize(Directory[])では、この呼び出しコードをメモリにインデックスする操作RAM DirectoryのIndexWriterをオフにして、すべてのdocumentがRAM Directoryに入るようにします.RAM Directoryのインスタンスを作成する場合は、パラメータなしの構築方法を使用するか、ファイルパスを指定してディスク内のインデックスをメモリにロードできます.
***2,相関度ソート,Luceneの検索結果はデフォルトで相関度ソートされているが,相関度とは文書のスコアである.Luceneには、検索結果をある基準で評価し、スコアの高低で結果をソートする採点メカニズムがあります.
a)文書のスコアは,ユーザが入力したキーワードに関係し,リアルタイム演算の結果である.スコアは、キーワードがドキュメントに表示される位置や回数などの影響を受けます.
b)BoostがLuceneのクエリ結果に影響するソートを利用して、DocumentのBoostを設定することによって文書の重みに影響して、クエリ結果の順序を制御する目的を達成することができる:Document.setBoost(float).デフォルト値は1 fで、値が大きいほど得点が高くなります.
c)クエリー時にFiledにboostを指定することもできます.同じtermが異なるfieldに属する場合、fieldのboostが異なると、その属するファイルの得点も異なる.后面
***3,Analyzer,分詞器,テキストリソースを分割し,テキストを規則的にインデックス可能な最小単位(キーワード)に分割する.
英語の分詞については、句読点、空白などによって単語を分割し、比較的簡単です.中国語の分詞は複雑で、例えば「中華人民共和国」は「中華」、「人民」、「共和国」に分けることができるが、「華人」という言葉(意味に合わない)はあるべきではない.
中国語の分詞のいくつかのよく使われる方式:a)単字分詞は、中国語の1字1字に従って分詞することである.私たちは中国人で、効果:私たちは中国人です.(StandardAnalyzerはそうです).b)二分法:二つの字で切り分ける.私たちは中国人で、効果:私たちは中国人です.(CJKAnalyzerはそうです).c)辞書分詞:あるアルゴリズムによって語を構築し,構築した辞書集合にマッチングし,マッチングしたら切り分けて語とする.通常、辞書の分詞は最も理想的な中国語の分詞アルゴリズムとされています.例えば、私たちは中国人で、効果は:私たち/中国人です.(MMAnalyzerを使用).
***4、Highlighter、ハイライト、一致するキーワードをハイライト表示します.3つの主要部分を含む:1)フォーマッタ:Formatter(SimpleHTML Formatterを使用して、構築時に接頭辞と接尾辞を指定します).2)採点器:Scorer(QueryScorerを使用).3)セグメント分割器:Fragmenter(SimpleFragmenterを使用して、構築時にキーワードが存在するコンテンツクリップの長さを指定します).
方法getBestFragment(Analyzer a,String fieldName,String text)によってハイライトを実現します.(ハイライトされたfieldにキーワードが表示されない場合はnullを返します).
*5クエリーには、クエリー文字列をQuery Parserで解析するか、APIを使用してクエリーを構築するかの2つの方法があります.Query Parserを使用する場合は大文字と小文字を区別しません.一般的なクエリーは次のとおりです.
1)TermQuery,Term(キーワード)によるクエリ(termの値は最終キーワード,英語はすべて小文字)である.   TermQuery(Term t);   syntax: propertyName:keyword;
2)RangeQuery、範囲クエリーを指定します.   RangeQuery(Term lowerTerm, Term upperTerm, boolean inclusive);syntax:propertyName:[lower TO upper](lowerとupperを含む)syntax:propertyName:{lower TO upper}(lowerとupperを含まない);
3)PrefixQuery,プレフィックスクエリ.   PrefixQuery(Term prefix);   syntax:propertyName:prefix*;
4)WildcardQuery,ワイルドカードクエリ,「?」は1文字、*は0文字以上を表します.WildcardQuery(Term term);   syntax: propertyName:chars*chars?chars
5)MultiFieldQueryParser、複数のFieldでクエリー.   queryParser = MultiFieldQueryParser(String[] fields, Analyzer analyzer);   Query query = parse(String query);6)BooleanQuery,ブールクエリ.これは組み合わせのQueryで、いろいろなQueryを追加して彼らの論理関係を明らかにすることができます.   TermQuery q1 = new TermQuery(new Term("title","javadoc"));   TermQuery q2 = new TermQuery(new Term("content","term"));   BooleanQuery boolQuery = new BooleanQuery();   boolQuery.add(q1, Occur.MUST);   boolQuery.add(q2, Occur.MUST_NOT);      Occur.MUST、現れなければなりません.   Occur.MUST_NOTは、必ず現れず、単独で使用しないでください.   Occur.SHOULDは、SHOULDが1つしかない場合は必ず現れ、1つ以上の場合はまたはの関係になります.
syntax:+-AND NOT OR(大文字でなければなりません).