Lucene---全文検索(問題分析)



インデックス作成時の処理:
 
一、単語で区切られますか?
1、Field.Index.ANALYZED:転送フィールドは単語に分類され、分詞によって検索されます。
2,Field.Index.NOT_ANALYZED:伝えられたフィールドは単語に分類されず、(元の値)によって検索されます。
3、Field.Index.NO:分詞に参加しなくても、検索に参加しません。
 
二、長期化されてファイルに保存されていますか?
1、Field.Store.YES:インデックスは持続化されます。検索する時、該当の値が調べられます。
2,Field.Store.NO:インデックスの場合は永続化されません。保存されません。
 
問題1:同時にindex_を配合するno storeいいえ、プログラムはエラーを報告します。このような場合は保存していませんので、
 

Lucene Dcumentに以下のFieldを追加します。
Field(path,notuanalyzed,store.yes)
Field(content,anlyzed,store.yes)
Field(name,notcanalyzed,store.no)
 
1,pathで検索すると、分詞がないので、(全パスで検索する)しか使えません。
2,contentで検索すると、任意の値を見つけることができます。
3、nameで検索すると、フルネームでしか検索できませんが、インデックスに参加しています。自身は持っていませんので、自分の値を得ることはできません。しかし、同じdocumentの値を得ることができます。
 
 
-----------------------------------------------
検索実行時の処理:
 
どのような方法で検索しますか?
1,Boolean Clause.Ocur.Must:
2,Boolean Clause.Ocur.SHOLD:
3,Boolean Clause.Ocur.Must_NOT:
以上の主なフィールドの統合検索は、sqlの意味と一致します。
--------------------------------------------
 
問題:
 
1、ペアで複数の検索をして、「多い」方を索引で検索すると、複数の「一」に関する情報がリンクされます。この場合は、Luceneで提供するフィルタDuplicteFilterが必要です。
 
2,並べ替えの問題、Luceneは多種の並べ替えを提供しましたが、時間の順序付けについては、文字列のcompreToのタイプによって比較されますので、同じフォーマットであれば並べ替えができます。
 
3,BooleanQueryを使って検索する時、他のクエリを統合して(福建省|上海)+上海のようなタイプの検索グループを検索することができます。
 
4、MultifieldQueryParser()が検索を行う場合、スペースプラス記号などの特殊文字列だけが処理されます。例えば、「振り替えリスト」が検出されます。
调达票や人员の情报は、调节の対応する情报が见つからないため、彼に分词し、IKAAnalyzerで停词処理しました。
 
//    
IKSegmentation ikSegmentation = new IKSegmentation(
					new StringReader(queryValue), true);
			StringBuffer segmentCombine = new StringBuffer();
			segmentCombine.append("\"" + queryValue + "\"");
			segmentCombine.append(" ");
			for (Lexeme lexeme = null; (lexeme = ikSegmentation.next()) != null;) {
				segmentCombine.append(lexeme.getLexemeText());
				segmentCombine.append(" ");
			}
			queryValue = segmentCombine.toString();
			
			Query q2 = MultiFieldQueryParser.parse(Version.LUCENE_30,
					queryValue, indexFields, clauses, getAnalyzer());
			((BooleanQuery) query).add(q2, BooleanClause.Occur.MUST);
 
5、高さを返し、関連する文字列のサイズを返します。
Simple HTMLFormater
Gighlighter.set Text Fragmenter(new SimpleFrangenter(n));
 
6,luceneで設定した戻りのデフォルトの本数は100(設定可能)で、ページ別に中間検索がなく、自分で必要な本数を取り出してから該当する演算を行います。
 
7,照会時に「open too many files」errorが現れたのは,Searchがオフになっていないからです。
理由:
NIOFS DirectoryがパラメータとしてIndexSearchに伝達されていない場合、indexSearch.closeは本当の意味でクローズされていません。IndexReaderに任せているので、自分でsearch.get IndexReader().close()をお願いします。
 
8,クエリを行うと、Luceneは対応するインデックスを全部メモリにロードします。インデックスが大きすぎると、消費メモリが足りなくなります。Searchを一例に設定して閉じません。
9,類似度問題(各属性設定参照ドキュメント)Simillaritクラスを書き換えます。
 
10,重い問題に行って、Lucene自身はDuplicteFilterを提供して再設定に行きますが、このFilterは問題があって、需要を満たすことができません。
例えば:
メインテーブルID:aa-xx-yy title:フォームの問題
 
表id:aa pid:aa-xy-yy content:こんにちは。
id:bb pid:aa-xy-yy content:ありがとうございます。
 
DupllicateFilterにpidをセットして重い場合、デフォルトでは最後の一つを取って、第一条をフィルタリングします。つまり、あなたが調べてください。「こんにちは」という場合、メインテーブルに関連しない「フォームの問題」を調べてください。ありがとうございます。
 
解決:このクラスの一つの方法をFilteredQueryによって書き換えます。(ファイルをアップロードする中で)利用できません。まだ解決策が見つからないです。
 

11, IKQueryParser , ,

“ ” , “ ”,“ ” , “ ”  “ ”

4 , , ik MUST ,,,--- IKQueryParser

 

=-----------------------------------------------------------------

 

12,

( ) ,lucene NumericRangeQuery TermRangeQuery ,

13,

lucene sort = new Sort(sortFields.toArray(sortArray)); , , ,,

14,

, query , , ,,,

,, , query, query ,

 

 

/**
 * 
 */
package com.fdauto.bws.business.module.lucene;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.BooleanClause.Occur;

import org.wltea.analyzer.IKSegmentation;
import org.wltea.analyzer.Lexeme;

/**
 * IK     
 *                   
 *                 
 *   IK Analyzer V3     
 * 
 *
 */
public final class BWSQueryParser {
	
	
	//               
	private static ThreadLocal<Map<String , TokenBranch>> keywordCacheThreadLocal 
			= new ThreadLocal<Map<String , TokenBranch>>();
	
	
	//          
	private static boolean isMaxWordLength = false;

	

	/**
	 *       
	 * isMaxWordLength = true         
	 * @param isMaxWordLength
	 */
	//public static void setMaxWordLength(boolean isMaxWordLength) {
		//BWSQueryParser.isMaxWordLength = isMaxWordLength ;
	//}
	
	/**
	 *   query  
	 *   Query      
	 * @param queries
	 * @return
	 */
	private static Query optimizeQueries(List<Query> queries,boolean exactMatch){	
		//    branch    query
		if(queries.size() == 0){
			return null;
		}else if(queries.size() == 1){
			return queries.get(0);
		}else{
			BooleanQuery mustQueries = new BooleanQuery();
			if(exactMatch){
				for(Query q : queries){
					mustQueries.add(q, Occur.MUST);
				}
			}else{
				for(Query q : queries){
					mustQueries.add(q, Occur.SHOULD);
				}
			}
			return mustQueries;
		}			
	}
	
	/**
	 *            
	 * @return
	 */
	private static Map<String , TokenBranch> getTheadLocalCache(){
		Map<String , TokenBranch> keywordCache = keywordCacheThreadLocal.get();
		if(keywordCache == null){
			 keywordCache = new HashMap<String , TokenBranch>(4);
			 keywordCacheThreadLocal.set(keywordCache);
		}
		return keywordCache;
	}
	
	/**
	 *           
	 * @param query
	 * @return
	 */
	private static TokenBranch getCachedTokenBranch(String query){
		Map<String , TokenBranch> keywordCache = getTheadLocalCache();
		return keywordCache.get(query);
	}
	
	/**
	 *           
	 * @param query
	 * @return
	 */
	private static void cachedTokenBranch(String query , TokenBranch tb){
		Map<String , TokenBranch> keywordCache = getTheadLocalCache();
		keywordCache.put(query, tb);
	}
		
	
	/**
	 *      (     ) Field    
	 * @param field
	 * @param query
	 * @return
	 * @throws IOException
	 */
	private static Query _parse(String field , String query,boolean exactMatch) throws IOException{
		if(field == null){
			throw new IllegalArgumentException("parameter \"field\" is null");
		}

		if(query == null || "".equals(query.trim())){
			return new TermQuery(new Term(field));
		}
		
		//           query   TokenBranch
		TokenBranch root = getCachedTokenBranch(query);
		if(root != null){
			return optimizeQueries(root.toQueries(field,exactMatch),exactMatch); 
		}else{
			
			
			
			//System.out.println(System.currentTimeMillis());
			root = new TokenBranch(null);	
			if(!query.startsWith("\"")&&!query.endsWith("\"")){
				//     q    
				StringReader input = new StringReader(query.trim());
				IKSegmentation ikSeg = new IKSegmentation(input , isMaxWordLength);
				for(Lexeme lexeme = ikSeg.next() ; lexeme != null ; lexeme = ikSeg.next()){
					//      
					root.accept(lexeme);
				}
			}else{
				//           ,   (  "   " ,     "   "                  "   " "  "     )
				//      coord()        ,    
				String[] querys=query.replace("\"", "").split("-");
				for(String queryValue:querys){
					Lexeme lexeme=new Lexeme(0,0,queryValue.length(),0);
					lexeme.setLexemeText(queryValue);
					root.accept(lexeme);
				}
				if(query.length()!=1){
					String queryTemp=query.replaceAll("-", "");
					Lexeme lexeme=new Lexeme(0,0,queryTemp.length(),0);
					lexeme.setLexemeText(queryTemp);
					root.accept(lexeme);
				}
			}
			//          
			cachedTokenBranch(query , root);
			return optimizeQueries(root.toQueries(field,exactMatch), exactMatch);
		}
	}
	
	/**
	 *    , Field    
	 * @param field -- Document field name
	 * @param query -- keyword
	 * @return Query       
	 * @throws IOException
	 */
	public static Query parse(String field , String query,boolean exactMatch) throws IOException{
		if(field == null){
			throw new IllegalArgumentException("parameter \"field\" is null");
		}
		String[] qParts = query.split("\\s");
		if(qParts.length > 1){			
			BooleanQuery resultQuery = new BooleanQuery();
			for(String q : qParts){
				//               
				if("".equals(q)){
					continue;
				}
				Query partQuery = _parse(field , q,exactMatch);
				if(partQuery != null && 
				          (!(partQuery instanceof BooleanQuery) || ((BooleanQuery)partQuery).getClauses().length>0)){
					if(exactMatch)
						resultQuery.add(partQuery, Occur.MUST);
					else
						resultQuery.add(partQuery, Occur.SHOULD);
				}
			}
			return resultQuery;
		}else{
			return _parse(field , query,exactMatch);
		}
	}
	
	
	
	/**
	 *  Field,   , Occur    
	 * @param fields -- Document fields name
	 * @param query	-- keyword
	 * @param flags -- BooleanClause
	 * @return Query       
	 * @throws IOException
	 */
	public static Query parseMultiField(String[] fields , String query ,  BooleanClause.Occur[] flags,boolean exactMatch) throws IOException{
		if(fields == null){
			throw new IllegalArgumentException("parameter \"fields\" is null");
		}
		if(flags == null){
			throw new IllegalArgumentException("parameter \"flags\" is null");
		}
		
		if (flags.length != fields.length){
		      throw new IllegalArgumentException("flags.length != fields.length");
		}		
		
		BooleanQuery resultQuery = new BooleanQuery();		
		for(int i = 0; i < fields.length; i++){
			if(fields[i] != null){
				Query partQuery = parse(fields[i] , query,exactMatch);
				if(partQuery != null && 
				          (!(partQuery instanceof BooleanQuery) || ((BooleanQuery)partQuery).getClauses().length>0)){
					resultQuery.add(partQuery, flags[i]); 
				}
			}			
		}		
		return resultQuery;
	}


	/**
	 *  Field,   , Occur    
	 * @param fields
	 * @param queries
	 * @param flags
	 * @return Query       
	 * @throws IOException
	 */
	public static Query parseMultiField(String[] fields , String[] queries , BooleanClause.Occur[] flags,boolean exactMatch) throws IOException{
		if(fields == null){
			throw new IllegalArgumentException("parameter \"fields\" is null");
		}				
		if(queries == null){
			throw new IllegalArgumentException("parameter \"queries\" is null");
		}
		if(flags == null){
			throw new IllegalArgumentException("parameter \"flags\" is null");
		}
		
	    if (!(queries.length == fields.length && queries.length == flags.length)){
	        throw new IllegalArgumentException("queries, fields, and flags array have have different length");
	    }

	    BooleanQuery resultQuery = new BooleanQuery();		
		for(int i = 0; i < fields.length; i++){
			if(fields[i] != null){
				Query partQuery = parse(fields[i] , queries[i], exactMatch);
				if(partQuery != null && 
				          (!(partQuery instanceof BooleanQuery) || ((BooleanQuery)partQuery).getClauses().length>0)){
					resultQuery.add(partQuery, flags[i]); 
				}
			}			
		}		
		return resultQuery;
	}	
	/**
	 *     
	 *         ,               
	 *
	 */
	private static class TokenBranch{
		
		private static final int REFUSED = -1;
		private static final int ACCEPTED = 0;
		private static final int TONEXT = 1;
		
		//       
		private int leftBorder;
		//       
		private int rightBorder;
		//       
		private Lexeme lexeme;
		//            
		private List<TokenBranch> acceptedBranchs;
		//            
		private TokenBranch nextBranch;
		
		TokenBranch(Lexeme lexeme){
			if(lexeme != null){
				this.lexeme = lexeme;
				//   branch     
				this.leftBorder = lexeme.getBeginPosition();
				this.rightBorder = lexeme.getEndPosition();
			}
		}
		
		public int getLeftBorder() {
			return leftBorder;
		}

		public int getRightBorder() {
			return rightBorder;
		}

		public Lexeme getLexeme() {
			return lexeme;
		}

		public List<TokenBranch> getAcceptedBranchs() {
			return acceptedBranchs;
		}

		public TokenBranch getNextBranch() {
			return nextBranch;
		}

		public int hashCode(){
			if(this.lexeme == null){
				return 0;
			}else{
				return this.lexeme.hashCode() * 37;
			}
		}
		
		public boolean equals(Object o){			
			if(o == null){
				return false;
			}		
			if(this == o){
				return true;
			}
			if(o instanceof TokenBranch){
				TokenBranch other = (TokenBranch)o;
				if(this.lexeme == null ||
						other.getLexeme() == null){
					return false;
				}else{
					return this.lexeme.equals(other.getLexeme());
				}
			}else{
				return false;
			}			
		}	
		
		/**
		 *       
		 * @param _lexeme
		 * @return     branch        
		 */
		boolean accept(Lexeme _lexeme){
			
			/*
			 *     lexeme     branch       
			 * acceptType : REFUSED      
			 * acceptType : ACCEPTED   
			 * acceptType : TONEXT           
			 */			
			int acceptType = checkAccept(_lexeme);			
			switch(acceptType){
			case REFUSED:
				// REFUSE   
				return false;
				
			case ACCEPTED : 
				if(acceptedBranchs == null){
					//  branch   branch,      branch 
					acceptedBranchs = new ArrayList<TokenBranch>(2);
					acceptedBranchs.add(new TokenBranch(_lexeme));					
				}else{
					boolean acceptedByChild = false;
					//  branch   branch,     branch  
					for(TokenBranch childBranch : acceptedBranchs){
						acceptedByChild = childBranch.accept(_lexeme) || acceptedByChild;
					}
					//      branch    ,    branch  
					if(!acceptedByChild){
						acceptedBranchs.add(new TokenBranch(_lexeme));
					}					
				}
				//  branch      
				if(_lexeme.getEndPosition() > this.rightBorder){
					this.rightBorder = _lexeme.getEndPosition();
				}
				break;
				
			case TONEXT : 
				// lexeme    branch     
				if(this.nextBranch == null){
					//         ,           
					this.nextBranch = new TokenBranch(null);
				}
				this.nextBranch.accept(_lexeme);
				break;
			}

			return true;
		}
		
		/**
		 *        Query  
		 * @return
		 */
		List<Query> toQueries(String fieldName,boolean exactMatch){			
			List<Query> queries = new ArrayList<Query>(1);			
 			//    branch  query
			if(lexeme != null){
				queries.add(new TermQuery(new Term(fieldName , lexeme.getLexemeText())));
			}			
			//  child branch  query
			if(acceptedBranchs != null && acceptedBranchs.size() > 0){
				if(acceptedBranchs.size() == 1){
					Query onlyOneQuery = optimizeQueries(acceptedBranchs.get(0).toQueries(fieldName,exactMatch),exactMatch);
					if(onlyOneQuery != null){
						queries.add(onlyOneQuery);
					}					
				}else{
					BooleanQuery orQuery = new BooleanQuery();
					for(TokenBranch childBranch : acceptedBranchs){
						Query childQuery = optimizeQueries(childBranch.toQueries(fieldName,exactMatch),exactMatch);
						if(childQuery != null){
							orQuery.add(childQuery, Occur.SHOULD);
						}
					}
					if(orQuery.getClauses().length > 0){
						queries.add(orQuery);
					}
				}
			}			
			//  nextBranch query
			if(nextBranch != null){				
				queries.addAll(nextBranch.toQueries(fieldName,exactMatch));
			}
			return queries;	
		}
		
		/**
		 *      lexeme      branch  
		 * @param lexeme
		 * @return        
		 */
		private int checkAccept(Lexeme _lexeme){
			int acceptType = 0;
			
			if(_lexeme == null){
				throw new IllegalArgumentException("parameter:lexeme is null");
			}
			
			if(null == this.lexeme){//   branch      (ROOT)   
				if(this.rightBorder > 0  //    branch      lexeme
						&& _lexeme.getBeginPosition() >= this.rightBorder){
					//_lexeme      branch   
					acceptType = TONEXT;
				}else{
					acceptType = ACCEPTED;
				}				
			}else{//   branch         
				
				if(_lexeme.getBeginPosition() < this.lexeme.getBeginPosition()){
					//_lexeme      this.lexeme   (         )
					acceptType = REFUSED;
				}else if(_lexeme.getBeginPosition() >= this.lexeme.getBeginPosition()
							&& _lexeme.getBeginPosition() < this.lexeme.getEndPosition()){
					// _lexeme   this.lexeme  
					acceptType = REFUSED;
				}else if(_lexeme.getBeginPosition() >= this.lexeme.getEndPosition()
							&& _lexeme.getBeginPosition() < this.rightBorder){
					//_lexeme   this.lexeme    ,  _lexeme      branch  
					acceptType = ACCEPTED;
				}else{//_lexeme.getBeginPosition() >= this.rightBorder
					//_lexeme      branch   
					acceptType=  TONEXT;
				}
			}
			return acceptType;
		}
	
	}
}
 
 
 
 
 
package com.fdauto.doc;

import org.apache.lucene.search.Similarity;

public class MySimilarity extends Similarity {

	/**
	 *       ,        
	 *  :                
	 */
	@Override
	public float coord(int overlap, int maxOverlap) {
		// TODO Auto-generated method stub
		return 1.0f;
	}

	/**
	 *       , Term="  "
	 *        ,   ,           
	 *
	 */
	@Override
	public float idf(int docFreq, int numDocs) {
		// TODO Auto-generated method stub
		return 1.0f;
	}

	/**
	 *            ,    ,    
	 * 
	 */
	@Override
	public float lengthNorm(String fieldName, int numTokens) {
		// TODO Auto-generated method stub
		return 1.0f;
	}

	/**
	 *          
	 */
	@Override
	public float queryNorm(float sumOfSquaredWeights) {
		// TODO Auto-generated method stub
		return 1.0f;
	}

	/**
	 *       ,     
	 * "    " "       "        
	 * 
	 */
	@Override
	public float sloppyFreq(int distance) {
		// TODO Auto-generated method stub
		return 1.0f / (distance + 1);
	}

	/**
	 *          term       
	 */
	@Override
	public float tf(float freq) {
		// TODO Auto-generated method stub
		return 1.0f;
	}

}


/**
 * 
 * 
score(q,d)   =   (6)coord(q,d)  ·  (3)queryNorm(q)  · ∑( (4)tf(t in d)  ·  (5)idf(t)2  ·  t.getBoost() ·  (1)norm(t,d) )

t in q

norm(t,d)   =   doc.getBoost()  ·  (2)lengthNorm(field)  ·  ∏f.getBoost()

                                                                           field f in d named as t

        :
 * 
 */
 
 
Luceneではwikiの が に であり、http://wiki.apache.org/lucene-java/LuceneFAQ#Why_ラム.I_getting_ IOException_that.says_.22 Too_マンリーopen_files.2.3 Fを することができます。
 
どうやって を げますか?
インデックスを める :http://wiki.apache.org/lucene-java/ImproveSearchingSpeed