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