This commit is contained in:
yfujita 2014-03-16 17:18:02 +09:00
parent 789949fe3b
commit 69ec8f429a
8 changed files with 306 additions and 1 deletions

View file

@ -127,6 +127,8 @@ public class Constants extends CoreLibConstants {
public static final String WEB_API_SUGGEST_PROPERTY = "web.api.suggest";
public static final String WEB_API_SPELLCHECK_PROPERTY = "web.api.spellcheck";
public static final String WEB_API_ANALYSIS_PROPERTY = "web.api.analysis";
public static final String WEB_DESIGN_EDITOR_PROPERTY = "design.editor";

View file

@ -52,6 +52,7 @@ import jp.sf.fess.db.exentity.SearchLog;
import jp.sf.fess.db.exentity.UserInfo;
import jp.sf.fess.entity.FieldAnalysisResponse;
import jp.sf.fess.entity.LoginInfo;
import jp.sf.fess.entity.SpellCheckResponse;
import jp.sf.fess.entity.SuggestResponse;
import jp.sf.fess.form.IndexForm;
import jp.sf.fess.helper.CrawlingConfigHelper;
@ -115,6 +116,8 @@ public class IndexAction {
protected static final int DEFAULT_SUGGEST_PAGE_SIZE = 5;
protected static final int DEFAULT_SPELLCHECK_PAGE_SIZE = 5;
protected static final Pattern FIELD_EXTRACTION_PATTERN = Pattern
.compile("^([a-zA-Z0-9_]+):.*");
@ -590,6 +593,65 @@ public class IndexAction {
return null;
}
@Execute(validator = false)
public String spellCheckApi() {
if (Constants.FALSE.equals(crawlerProperties.getProperty(
Constants.WEB_API_SPELLCHECK_PROPERTY, Constants.TRUE))) {
WebApiUtil.setError(9, "Unsupported operation.");
return null;
}
if (indexForm.fn == null || indexForm.fn.length == 0) {
WebApiUtil.setError(2, "The field name is empty.");
return null;
}
if (StringUtil.isBlank(indexForm.query)) {
WebApiUtil.setError(3, "Your query is empty.");
return null;
}
if (StringUtil.isBlank(indexForm.num)) {
indexForm.num = String.valueOf(DEFAULT_SPELLCHECK_PAGE_SIZE);
}
int num = Integer.parseInt(indexForm.num);
if (num > getMaxPageSize()) {
num = getMaxPageSize();
}
final String[] fieldNames = indexForm.fn;
final String[] labels = indexForm.fields.get("label");
final List<SpellCheckResponse> spellCheckResultList = new ArrayList<SpellCheckResponse>();
WebApiUtil.setObject("spellCheckResultList", spellCheckResultList);
final List<String> spellCheckFieldName = Arrays.asList(fieldNames);
WebApiUtil.setObject("spellCheckFieldName", spellCheckFieldName);
final List<String> labelList;
if (labels == null) {
labelList = new ArrayList<String>();
} else {
labelList = Arrays.asList(labels);
}
try {
final SpellCheckResponse spellCheckResponse = searchService
.getSpellCheckResponse(indexForm.query,
spellCheckFieldName, labelList, num);
if (!spellCheckResponse.isEmpty()) {
spellCheckResultList.add(spellCheckResponse);
}
WebApiUtil.setObject("spellCheckRecordCount", 1);
} catch (final Exception e) {
WebApiUtil.setError(1, e);
}
return null;
}
@Execute(validator = false)
public String analysisApi() {
if (Constants.FALSE.equals(crawlerProperties.getProperty(

View file

@ -27,10 +27,12 @@ public class BaseApiManager {
protected static final String SUGGEST_API = "/suggestApi";
protected static final String SPELLCHECK_API = "/spellCheckApi";
protected static final String SEARCH_API = "/searchApi";
protected static enum FormatType {
SEARCH, LABEL, SUGGEST, ANALYSIS, HOTSEARCHWORD, FAVORITE, FAVORITES, OTHER;
SEARCH, LABEL, SUGGEST, SPELLCHECK, ANALYSIS, HOTSEARCHWORD, FAVORITE, FAVORITES, OTHER;
}
public BaseApiManager() {
@ -48,6 +50,8 @@ public class BaseApiManager {
return FormatType.LABEL;
} else if (FormatType.SUGGEST.name().equals(type)) {
return FormatType.SUGGEST;
} else if (FormatType.SPELLCHECK.name().equals(type)) {
return FormatType.SPELLCHECK;
} else if (FormatType.ANALYSIS.name().equals(type)) {
return FormatType.ANALYSIS;
} else if (FormatType.HOTSEARCHWORD.name().equals(type)) {

View file

@ -36,6 +36,7 @@ import jp.sf.fess.api.WebApiRequest;
import jp.sf.fess.api.WebApiResponse;
import jp.sf.fess.db.allcommon.CDef;
import jp.sf.fess.entity.FieldAnalysisResponse;
import jp.sf.fess.entity.SpellCheckResponse;
import jp.sf.fess.entity.SuggestResponse;
import jp.sf.fess.entity.SuggestResponse.SuggestResponseList;
import jp.sf.fess.util.ComponentUtil;
@ -85,6 +86,9 @@ public class JsonApiManager extends BaseApiManager implements WebApiManager {
case SUGGEST:
processSuggestRequest(request, response, chain);
break;
case SPELLCHECK:
processSpellCheckRequest(request, response, chain);
break;
case ANALYSIS:
processAnalysisRequest(request, response, chain);
break;
@ -423,6 +427,90 @@ public class JsonApiManager extends BaseApiManager implements WebApiManager {
}
protected void processSpellCheckRequest(final HttpServletRequest request,
final HttpServletResponse response, final FilterChain chain) {
int status = 0;
String errMsg = StringUtil.EMPTY;
final StringBuilder buf = new StringBuilder(255);
try {
chain.doFilter(new WebApiRequest(request, SPELLCHECK_API),
new WebApiResponse(response));
WebApiUtil.validate();
final Integer spellCheckRecordCount = WebApiUtil
.getObject("spellCheckRecordCount");
final List<SpellCheckResponse> spellCheckResultList = WebApiUtil
.getObject("spellCheckResultList");
final List<String> spellCheckFieldName = WebApiUtil
.getObject("spellCheckFieldName");
buf.append("\"recordCount\":");
buf.append(spellCheckRecordCount);
if (spellCheckResultList.size() > 0) {
buf.append(',');
buf.append("\"result\":[");
boolean first1 = true;
for (int i = 0; i < spellCheckResultList.size(); i++) {
final SuggestResponse suggestResponse = spellCheckResultList
.get(i);
for (final Map.Entry<String, List<String>> entry : suggestResponse
.entrySet()) {
final String fn = spellCheckFieldName.get(i);
if (!first1) {
buf.append(',');
} else {
first1 = false;
}
final SuggestResponseList srList = (SuggestResponseList) entry
.getValue();
buf.append("{\"token\":");
buf.append(escapeJson(entry.getKey()));
buf.append(", \"fn\":");
buf.append(escapeJson(fn));
buf.append(", \"startOffset\":");
buf.append(Integer.toString(srList.getStartOffset()));
buf.append(", \"endOffset\":");
buf.append(Integer.toString(srList.getEndOffset()));
buf.append(", \"numFound\":");
buf.append(Integer.toString(srList.getNumFound()));
buf.append(", ");
buf.append("\"result\":[");
boolean first2 = true;
for (final String value : srList) {
if (!first2) {
buf.append(',');
} else {
first2 = false;
}
buf.append(escapeJson(value));
}
buf.append("]}");
}
}
buf.append(']');
}
} catch (final Exception e) {
if (e instanceof WebApiException) {
status = ((WebApiException) e).getStatusCode();
} else {
status = 1;
}
errMsg = e.getMessage();
if (logger.isDebugEnabled()) {
logger.debug("Failed to process a spellcheck request.", e);
}
}
writeJsonResponse(status, buf.toString(), errMsg);
}
protected void processAnalysisRequest(final HttpServletRequest request,
final HttpServletResponse response, final FilterChain chain) {

View file

@ -35,6 +35,7 @@ import jp.sf.fess.api.WebApiRequest;
import jp.sf.fess.api.WebApiResponse;
import jp.sf.fess.db.allcommon.CDef;
import jp.sf.fess.entity.FieldAnalysisResponse;
import jp.sf.fess.entity.SpellCheckResponse;
import jp.sf.fess.entity.SuggestResponse;
import jp.sf.fess.entity.SuggestResponse.SuggestResponseList;
import jp.sf.fess.util.ComponentUtil;
@ -82,6 +83,9 @@ public class XmlApiManager extends BaseApiManager implements WebApiManager {
case SUGGEST:
processSuggestRequest(request, response, chain);
break;
case SPELLCHECK:
processSpellCheckRequest(request, response, chain);
break;
case ANALYSIS:
processAnalysisRequest(request, response, chain);
break;
@ -367,6 +371,86 @@ public class XmlApiManager extends BaseApiManager implements WebApiManager {
writeXmlResponse(status, buf.toString(), errMsg);
}
protected void processSpellCheckRequest(final HttpServletRequest request,
final HttpServletResponse response, final FilterChain chain) {
int status = 0;
String errMsg = StringUtil.EMPTY;
final StringBuilder buf = new StringBuilder(255);
try {
chain.doFilter(new WebApiRequest(request, SPELLCHECK_API),
new WebApiResponse(response));
WebApiUtil.validate();
final Integer spellCheckRecordCount = WebApiUtil
.getObject("spellCheckRecordCount");
final List<SpellCheckResponse> spellCheckResultList = WebApiUtil
.getObject("spellCheckResultList");
final List<String> spellCheckFieldName = WebApiUtil
.getObject("spellCheckFieldName");
buf.append("<record-count>");
buf.append(spellCheckRecordCount);
buf.append("</record-count>");
if (spellCheckResultList.size() > 0) {
buf.append("<result>");
for (int i = 0; i < spellCheckResultList.size(); i++) {
final SuggestResponse suggestResponse = spellCheckResultList
.get(i);
for (final Map.Entry<String, List<String>> entry : suggestResponse
.entrySet()) {
final SuggestResponseList srList = (SuggestResponseList) entry
.getValue();
final String fn = spellCheckFieldName.get(i);
buf.append("<suggest>");
buf.append("<token>");
buf.append(escapeXml(entry.getKey()));
buf.append("</token>");
buf.append("<fn>");
buf.append(escapeXml(fn));
buf.append("</fn>");
buf.append("<start-offset>");
buf.append(escapeXml(Integer.toString(srList
.getStartOffset())));
buf.append("</start-offset>");
buf.append("<end-offset>");
buf.append(escapeXml(Integer.toString(srList
.getEndOffset())));
buf.append("</end-offset>");
buf.append("<num-found>");
buf.append(escapeXml(Integer.toString(srList
.getNumFound())));
buf.append("</num-found>");
buf.append("<result>");
for (final String value : srList) {
buf.append("<value>");
buf.append(escapeXml(value));
buf.append("</value>");
}
buf.append("</result>");
buf.append("</suggest>");
}
}
buf.append("</result>");
}
} catch (final Exception e) {
if (e instanceof WebApiException) {
status = ((WebApiException) e).getStatusCode();
} else {
status = 1;
}
errMsg = e.getMessage();
if (logger.isDebugEnabled()) {
logger.debug("Failed to process a spellcheck request.", e);
}
}
writeXmlResponse(status, buf.toString(), errMsg);
}
protected String processAnalysisRequest(final HttpServletRequest request,
final HttpServletResponse response, final FilterChain chain) {

View file

@ -0,0 +1,10 @@
package jp.sf.fess.entity;
import org.apache.solr.client.solrj.response.QueryResponse;
public class SpellCheckResponse extends SuggestResponse {
public SpellCheckResponse(final QueryResponse queryResponse, final int num,
final String query) {
super(queryResponse, num, query);
}
}

View file

@ -35,10 +35,12 @@ import jp.sf.fess.entity.GeoInfo;
import jp.sf.fess.entity.MoreLikeThisInfo;
import jp.sf.fess.entity.SearchQuery;
import jp.sf.fess.entity.SearchQuery.SortField;
import jp.sf.fess.entity.SpellCheckResponse;
import jp.sf.fess.entity.SuggestResponse;
import jp.sf.fess.helper.QueryHelper;
import jp.sf.fess.helper.RoleQueryHelper;
import jp.sf.fess.solr.FessSolrQueryException;
import jp.sf.fess.suggest.SpellChecker;
import jp.sf.fess.suggest.SuggestConstants;
import jp.sf.fess.suggest.Suggester;
import jp.sf.fess.util.ComponentUtil;
@ -73,6 +75,9 @@ public class SearchService implements Serializable {
@Resource
protected Suggester suggester;
@Resource
protected SpellChecker spellChecker;
public Map<String, Object> getDocument(final String query) {
return getDocument(query, queryHelper.getResponseFields(), null);
}
@ -320,6 +325,47 @@ public class SearchService implements Serializable {
return suggestResponse;
}
public SpellCheckResponse getSpellCheckResponse(final String q,
final List<String> fieldNames, final List<String> labels,
final int rows) {
final Set<String> roleSet;
if (roleQueryHelper != null) {
roleSet = roleQueryHelper.build();
} else {
roleSet = new HashSet<>();
}
final List<String> roleList = new ArrayList<>(roleSet);
final String spellCheckQuery = spellChecker.buildSpellCheckQuery(q,
fieldNames, labels, roleList);
final long startTime = System.currentTimeMillis();
QueryResponse queryResponse = null;
final SolrQuery solrQuery = new SolrQuery();
if (StringUtil.isNotBlank(spellCheckQuery)) {
// query
solrQuery.setQuery(spellCheckQuery);
// size
solrQuery.setRows(rows);
//sort
solrQuery.setSort(SuggestConstants.SuggestFieldNames.COUNT,
SolrQuery.ORDER.desc);
if (queryHelper.getTimeAllowed() >= 0) {
solrQuery.setTimeAllowed(queryHelper.getTimeAllowed());
}
queryResponse = suggestSolrGroup.query(solrQuery,
SolrRequest.METHOD.POST);
}
final long execTime = System.currentTimeMillis() - startTime;
final SpellCheckResponse spellCheckResponse = new SpellCheckResponse(
queryResponse, rows, q);
spellCheckResponse.setExecTime(execTime);
return spellCheckResponse;
}
public FieldAnalysisResponse getFieldAnalysisResponse(
final String[] fieldNames, final String fieldValue) {
final FieldAnalysisRequest request = new FieldAnalysisRequest();

View file

@ -35,6 +35,15 @@
</initMethod>
</component>
<component name="spellchecker" class="jp.sf.fess.suggest.SpellChecker">
<property name="fuzzyValue">0.5</property>
<initMethod name="setConverter">
<arg>suggestIntegrateConverter</arg>
</initMethod>
<initMethod name="setNormalizer">
<arg>suggestIntegrateNormalizer</arg>
</initMethod>
</component>
<!-- Solr Group Configuration -->
<component name="suggestSolrProperties" class="org.codelibs.core.util.DynamicProperties">