This commit is contained in:
parent
789949fe3b
commit
69ec8f429a
8 changed files with 306 additions and 1 deletions
|
@ -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";
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
10
src/main/java/jp/sf/fess/entity/SpellCheckResponse.java
Normal file
10
src/main/java/jp/sf/fess/entity/SpellCheckResponse.java
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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">
|
||||
|
|
Loading…
Add table
Reference in a new issue