/**
* License Agreement for OpenSearchServer
*
* Copyright (C) 2012 Emmanuel Keller / Jaeksoft
*
* http://www.open-search-server.com
*
* This file is part of OpenSearchServer.
*
* OpenSearchServer is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenSearchServer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenSearchServer.
* If not, see <http://www.gnu.org/licenses/>.
**/
package com.jaeksoft.searchlib.analysis.filter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.TermQuery;
import com.jaeksoft.searchlib.Client;
import com.jaeksoft.searchlib.ClientCatalog;
import com.jaeksoft.searchlib.ClientCatalogItem;
import com.jaeksoft.searchlib.ClientFactory;
import com.jaeksoft.searchlib.SearchLibException;
import com.jaeksoft.searchlib.analysis.ClassPropertyEnum;
import com.jaeksoft.searchlib.analysis.FilterFactory;
import com.jaeksoft.searchlib.analysis.TokenTerm;
import com.jaeksoft.searchlib.function.expression.SyntaxError;
import com.jaeksoft.searchlib.query.ParseException;
import com.jaeksoft.searchlib.request.AbstractLocalSearchRequest;
import com.jaeksoft.searchlib.result.AbstractResultSearch;
import com.jaeksoft.searchlib.result.ResultDocument;
import com.jaeksoft.searchlib.schema.FieldValueItem;
public class IndexLookupFilter extends FilterFactory {
private String indexName = null;
private String requestName = null;
private String returnField = null;
private String requestedField = null;
private final int maxTokenSearch = ClientFactory.INSTANCE
.getBooleanQueryMaxClauseCount().getValue();
@Override
public void initProperties() throws SearchLibException {
super.initProperties();
List<String> values = new ArrayList<String>(0);
for (ClientCatalogItem item : ClientCatalog.getClientCatalog(null))
values.add(item.getIndexName());
addProperty(ClassPropertyEnum.INDEX_LIST, "", values.toArray(), 0, 0);
addProperty(ClassPropertyEnum.SEARCH_REQUEST, "", null, 20, 1);
addProperty(ClassPropertyEnum.REQUESTED_FIELD, "", null, 20, 1);
addProperty(ClassPropertyEnum.RETURN_FIELD, "", null, 30, 1);
}
@Override
public void checkValue(ClassPropertyEnum prop, String value)
throws SearchLibException {
if (prop == ClassPropertyEnum.INDEX_LIST)
indexName = value;
else if (prop == ClassPropertyEnum.SEARCH_REQUEST)
requestName = value;
else if (prop == ClassPropertyEnum.REQUESTED_FIELD)
requestedField = value;
else if (prop == ClassPropertyEnum.RETURN_FIELD)
returnField = value;
}
public void setProperties(String indexName, String requestName,
String requestedField, String returnField)
throws SearchLibException {
if (indexName != null)
getProperty(ClassPropertyEnum.INDEX_LIST).setValue(indexName);
if (requestName != null)
getProperty(ClassPropertyEnum.SEARCH_REQUEST).setValue(requestName);
if (requestedField != null)
getProperty(ClassPropertyEnum.REQUESTED_FIELD).setValue(
requestedField);
if (returnField != null)
getProperty(ClassPropertyEnum.RETURN_FIELD).setValue(returnField);
}
@Override
public TokenStream create(TokenStream tokenStream)
throws SearchLibException {
Client indexClient = ClientCatalog.getClient(indexName);
AbstractLocalSearchRequest searchRequest = (AbstractLocalSearchRequest) indexClient
.getNewRequest(requestName);
searchRequest.setDefaultOperator("OR");
return new IndexLookupTokenFilter(tokenStream, indexClient,
searchRequest, requestedField, returnField, maxTokenSearch);
}
public static class IndexLookupTokenFilter extends AbstractTermFilter {
private final Client indexClient;
private final AbstractLocalSearchRequest searchRequest;
private final String[] returnFields;
private final String requestedField;
private final int batchBuffer;
private final List<TokenTerm> collectedTokenBuffer;
private final List<TokenTerm> tokenQueue;
private int currentQueuePos;
public IndexLookupTokenFilter(TokenStream input, Client indexClient,
AbstractLocalSearchRequest searchRequest,
String requestedField, String returnField, int batchBuffer) {
super(input);
tokenQueue = new ArrayList<TokenTerm>(0);
this.batchBuffer = batchBuffer;
collectedTokenBuffer = new ArrayList<TokenTerm>(batchBuffer);
this.indexClient = indexClient;
this.searchRequest = searchRequest;
this.returnFields = StringUtils.split(returnField, '|');
this.requestedField = !StringUtils.isEmpty(requestedField) ? requestedField
: ArrayUtils.isEmpty(returnFields) ? null : returnFields[0];
}
private final boolean popToken() {
if (tokenQueue.size() == 0)
return false;
if (currentQueuePos == tokenQueue.size())
return false;
createToken(tokenQueue.get(currentQueuePos++));
return true;
}
private final void extractTokens(TokenTerm tokenTerm, int docId,
ResultDocument resultDoc) {
for (String returnField : returnFields) {
List<FieldValueItem> fieldValueItems = resultDoc
.getValues(returnField);
if (fieldValueItems == null)
continue;
for (FieldValueItem fieldValueItem : fieldValueItems)
tokenQueue.add(new TokenTerm(fieldValueItem.getValue(),
tokenTerm, returnField, docId));
}
}
private final void searchTokens() throws SearchLibException,
ParseException, SyntaxError, IOException {
TokenTerm mergedTokenTerm = new TokenTerm(collectedTokenBuffer);
searchRequest.reset();
BooleanQuery bq = new BooleanQuery();
for (TokenTerm tokenTerm : collectedTokenBuffer)
bq.add(new TermQuery(new Term(requestedField, tokenTerm.term)),
Occur.SHOULD);
searchRequest.setBoostedComplexQuery(bq);
searchRequest.setRows(collectedTokenBuffer.size());
AbstractResultSearch<?> result = (AbstractResultSearch<?>) indexClient
.request(searchRequest);
collectedTokenBuffer.clear();
if (result.getNumFound() == 0)
return;
int max = searchRequest.getEnd();
if (max > result.getNumFound())
max = result.getNumFound();
tokenQueue.clear();
currentQueuePos = 0;
for (int i = 0; i < max; i++) {
ResultDocument resultDoc = result.getDocument(i);
int docId = resultDoc.getDocId();
extractTokens(mergedTokenTerm, docId, resultDoc);
List<ResultDocument> joinResultDocuments = result
.getJoinDocumentList(i, null);
if (joinResultDocuments != null)
for (ResultDocument joinResultDocument : joinResultDocuments)
extractTokens(mergedTokenTerm, docId,
joinResultDocument);
}
}
@Override
public final boolean incrementToken() throws IOException {
try {
for (;;) {
if (popToken())
return true;
if (!input.incrementToken()) {
if (collectedTokenBuffer.size() == 0)
return false;
searchTokens();
continue;
}
collectedTokenBuffer.add(new TokenTerm(termAtt, posIncrAtt,
offsetAtt, typeAtt, flagsAtt));
if (collectedTokenBuffer.size() >= batchBuffer)
searchTokens();
}
} catch (SearchLibException e) {
throw new IOException(e);
} catch (ParseException e) {
throw new IOException(e);
} catch (SyntaxError e) {
throw new IOException(e);
}
}
}
}