diff --git a/src/main/java/org/codelibs/fess/api/gsa/GsaApiManager.java b/src/main/java/org/codelibs/fess/api/gsa/GsaApiManager.java index 27caf1f64..da44a1ce3 100644 --- a/src/main/java/org/codelibs/fess/api/gsa/GsaApiManager.java +++ b/src/main/java/org/codelibs/fess/api/gsa/GsaApiManager.java @@ -49,6 +49,7 @@ import org.codelibs.fess.api.WebApiRequest; import org.codelibs.fess.app.service.SearchService; import org.codelibs.fess.entity.FacetInfo; import org.codelibs.fess.entity.GeoInfo; +import org.codelibs.fess.entity.HighlightInfo; import org.codelibs.fess.entity.SearchRenderData; import org.codelibs.fess.entity.SearchRequestParams; import org.codelibs.fess.exception.InvalidAccessTokenException; @@ -433,7 +434,7 @@ public class GsaApiManager extends BaseApiManager implements WebApiManager { } } - protected static class GsaRequestParams implements SearchRequestParams { + protected static class GsaRequestParams extends SearchRequestParams { private final HttpServletRequest request; @@ -622,6 +623,10 @@ public class GsaApiManager extends BaseApiManager implements WebApiManager { return request.getParameter("sdh"); } + @Override + public HighlightInfo getHighlightInfo() { + return ComponentUtil.getViewHelper().createHighlightInfo(); + } } public void setGsaPathPrefix(final String gsaPathPrefix) { diff --git a/src/main/java/org/codelibs/fess/api/json/JsonApiManager.java b/src/main/java/org/codelibs/fess/api/json/JsonApiManager.java index 5e859f275..32acb97c5 100644 --- a/src/main/java/org/codelibs/fess/api/json/JsonApiManager.java +++ b/src/main/java/org/codelibs/fess/api/json/JsonApiManager.java @@ -40,6 +40,7 @@ import org.codelibs.fess.app.service.FavoriteLogService; import org.codelibs.fess.app.service.SearchService; import org.codelibs.fess.entity.FacetInfo; import org.codelibs.fess.entity.GeoInfo; +import org.codelibs.fess.entity.HighlightInfo; import org.codelibs.fess.entity.PingResponse; import org.codelibs.fess.entity.SearchRenderData; import org.codelibs.fess.entity.SearchRequestParams; @@ -674,7 +675,7 @@ public class JsonApiManager extends BaseJsonApiManager { } - protected static class JsonRequestParams implements SearchRequestParams { + protected static class JsonRequestParams extends SearchRequestParams { private final HttpServletRequest request; @@ -806,5 +807,9 @@ public class JsonApiManager extends BaseJsonApiManager { return request.getParameter("sdh"); } + @Override + public HighlightInfo getHighlightInfo() { + return ComponentUtil.getViewHelper().createHighlightInfo(); + } } } diff --git a/src/main/java/org/codelibs/fess/api/suggest/SuggestApiManager.java b/src/main/java/org/codelibs/fess/api/suggest/SuggestApiManager.java index ee674a00d..e7558f22f 100644 --- a/src/main/java/org/codelibs/fess/api/suggest/SuggestApiManager.java +++ b/src/main/java/org/codelibs/fess/api/suggest/SuggestApiManager.java @@ -35,6 +35,7 @@ import org.codelibs.fess.api.BaseJsonApiManager; import org.codelibs.fess.app.service.SearchService; import org.codelibs.fess.entity.FacetInfo; import org.codelibs.fess.entity.GeoInfo; +import org.codelibs.fess.entity.HighlightInfo; import org.codelibs.fess.entity.SearchRequestParams; import org.codelibs.fess.entity.SearchRequestParams.SearchRequestType; import org.codelibs.fess.exception.InvalidAccessTokenException; @@ -163,7 +164,7 @@ public class SuggestApiManager extends BaseJsonApiManager { writeJsonResponse(status, buf.toString(), errMsg); } - protected static class RequestParameter implements SearchRequestParams { + protected static class RequestParameter extends SearchRequestParams { private final String query; private final String[] fields; @@ -293,5 +294,10 @@ public class SuggestApiManager extends BaseJsonApiManager { public String getSimilarDocHash() { throw new UnsupportedOperationException(); } + + @Override + public HighlightInfo getHighlightInfo() { + return new HighlightInfo(); + } } } diff --git a/src/main/java/org/codelibs/fess/app/service/SearchService.java b/src/main/java/org/codelibs/fess/app/service/SearchService.java index d63e2e0e1..76759a7e6 100644 --- a/src/main/java/org/codelibs/fess/app/service/SearchService.java +++ b/src/main/java/org/codelibs/fess/app/service/SearchService.java @@ -111,13 +111,11 @@ public class SearchService { query = ComponentUtil.getQueryStringBuilder().params(params).build() + " sort:" + sortField; } final List> documentItems = - fessEsClient.search( - fessConfig.getIndexDocumentSearchIndex(), - fessConfig.getIndexDocumentType(), + fessEsClient.search(fessConfig.getIndexDocumentSearchIndex(), fessConfig.getIndexDocumentType(), searchRequestBuilder -> { queryHelper.processSearchPreference(searchRequestBuilder, userBean, query); return SearchConditionBuilder.builder(searchRequestBuilder).query(query).offset(pageStart).size(pageSize) - .facetInfo(params.getFacetInfo()).geoInfo(params.getGeoInfo()) + .facetInfo(params.getFacetInfo()).geoInfo(params.getGeoInfo()).highlightInfo(params.getHighlightInfo()) .similarDocHash(params.getSimilarDocHash()).responseFields(queryHelper.getResponseFields()) .searchRequestType(params.getType()).build(); }, (searchRequestBuilder, execTime, searchResponse) -> { diff --git a/src/main/java/org/codelibs/fess/app/web/admin/searchlist/ListForm.java b/src/main/java/org/codelibs/fess/app/web/admin/searchlist/ListForm.java index e684ce155..210aa67a8 100644 --- a/src/main/java/org/codelibs/fess/app/web/admin/searchlist/ListForm.java +++ b/src/main/java/org/codelibs/fess/app/web/admin/searchlist/ListForm.java @@ -26,6 +26,7 @@ import javax.validation.constraints.Size; import org.codelibs.core.lang.StringUtil; import org.codelibs.fess.entity.FacetInfo; import org.codelibs.fess.entity.GeoInfo; +import org.codelibs.fess.entity.HighlightInfo; import org.codelibs.fess.entity.SearchRequestParams; import org.codelibs.fess.mylasta.direction.FessConfig; import org.codelibs.fess.util.ComponentUtil; @@ -36,7 +37,7 @@ import org.lastaflute.web.validation.theme.conversion.ValidateTypeFailure; * @author shinsuke * @author Keiichi Watanabe */ -public class ListForm implements SearchRequestParams { +public class ListForm extends SearchRequestParams { @Size(max = 1000) public String q; @@ -117,6 +118,11 @@ public class ListForm implements SearchRequestParams { return null; } + @Override + public HighlightInfo getHighlightInfo() { + return new HighlightInfo(); + } + @Override public String getSort() { return sort; diff --git a/src/main/java/org/codelibs/fess/app/web/base/SearchForm.java b/src/main/java/org/codelibs/fess/app/web/base/SearchForm.java index 967ce7db7..9b95c5eb3 100644 --- a/src/main/java/org/codelibs/fess/app/web/base/SearchForm.java +++ b/src/main/java/org/codelibs/fess/app/web/base/SearchForm.java @@ -26,13 +26,14 @@ import javax.validation.constraints.Size; import org.codelibs.core.lang.StringUtil; import org.codelibs.fess.entity.FacetInfo; import org.codelibs.fess.entity.GeoInfo; +import org.codelibs.fess.entity.HighlightInfo; import org.codelibs.fess.entity.SearchRequestParams; import org.codelibs.fess.mylasta.direction.FessConfig; import org.codelibs.fess.util.ComponentUtil; import org.lastaflute.web.util.LaRequestUtil; import org.lastaflute.web.validation.theme.conversion.ValidateTypeFailure; -public class SearchForm implements SearchRequestParams { +public class SearchForm extends SearchRequestParams { public Map fields = new HashMap<>(); @@ -122,6 +123,11 @@ public class SearchForm implements SearchRequestParams { return ComponentUtil.getQueryHelper().getDefaultFacetInfo(); } + @Override + public HighlightInfo getHighlightInfo() { + return ComponentUtil.getViewHelper().createHighlightInfo(); + } + @Override public String getSort() { return sort; diff --git a/src/main/java/org/codelibs/fess/entity/HighlightInfo.java b/src/main/java/org/codelibs/fess/entity/HighlightInfo.java new file mode 100644 index 000000000..384076d65 --- /dev/null +++ b/src/main/java/org/codelibs/fess/entity/HighlightInfo.java @@ -0,0 +1,59 @@ +/* + * Copyright 2012-2019 CodeLibs Project and the Others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.codelibs.fess.entity; + +import org.codelibs.fess.mylasta.direction.FessConfig; +import org.codelibs.fess.util.ComponentUtil; + +public class HighlightInfo { + private String type; + private int fragmentSize; + private int numOfFragments; + + public HighlightInfo() { + FessConfig fessConfig = ComponentUtil.getFessConfig(); + this.type = fessConfig.getQueryHighlightType(); + this.fragmentSize = fessConfig.getQueryHighlightFragmentSizeAsInteger(); + this.numOfFragments = fessConfig.getQueryHighlightNumberOfFragmentsAsInteger(); + } + + public String getType() { + return type; + } + + public HighlightInfo type(String type) { + this.type = type; + return this; + } + + public int getFragmentSize() { + return fragmentSize; + } + + public HighlightInfo fragmentSize(int fragmentSize) { + this.fragmentSize = fragmentSize; + return this; + } + + public int getNumOfFragments() { + return numOfFragments; + } + + public HighlightInfo numOfFragments(int numOfFragments) { + this.numOfFragments = numOfFragments; + return this; + } +} diff --git a/src/main/java/org/codelibs/fess/entity/SearchRequestParams.java b/src/main/java/org/codelibs/fess/entity/SearchRequestParams.java index edcc77e7e..ecb1b2c72 100644 --- a/src/main/java/org/codelibs/fess/entity/SearchRequestParams.java +++ b/src/main/java/org/codelibs/fess/entity/SearchRequestParams.java @@ -24,53 +24,55 @@ import javax.servlet.http.HttpServletRequest; import org.codelibs.core.lang.StringUtil; -public interface SearchRequestParams { +public abstract class SearchRequestParams { - String AS_NQ = "nq"; + public static final String AS_NQ = "nq"; - String AS_OQ = "oq"; + public static final String AS_OQ = "oq"; - String AS_EPQ = "epq"; + public static final String AS_EPQ = "epq"; - String AS_Q = "q"; + public static final String AS_Q = "q"; - String AS_FILETYPE = "filetype"; + public static final String AS_FILETYPE = "filetype"; - String AS_SITESEARCH = "sitesearch"; + public static final String AS_SITESEARCH = "sitesearch"; - String AS_OCCURRENCE = "occt"; + public static final String AS_OCCURRENCE = "occt"; - String AS_TIMESTAMP = "timestamp"; + public static final String AS_TIMESTAMP = "timestamp"; - String getQuery(); + public abstract String getQuery(); - Map getFields(); + public abstract Map getFields(); - Map getConditions(); + public abstract Map getConditions(); - String[] getLanguages(); + public abstract String[] getLanguages(); - GeoInfo getGeoInfo(); + public abstract GeoInfo getGeoInfo(); - FacetInfo getFacetInfo(); + public abstract FacetInfo getFacetInfo(); - String getSort(); + public abstract HighlightInfo getHighlightInfo(); - int getStartPosition(); + public abstract String getSort(); - int getPageSize(); + public abstract int getStartPosition(); - String[] getExtraQueries(); + public abstract int getPageSize(); - Object getAttribute(String name); + public abstract String[] getExtraQueries(); - Locale getLocale(); + public abstract Object getAttribute(String name); - SearchRequestType getType(); + public abstract Locale getLocale(); - String getSimilarDocHash(); + public abstract SearchRequestType getType(); - default boolean hasConditionQuery() { + public abstract String getSimilarDocHash(); + + public boolean hasConditionQuery() { final Map conditions = getConditions(); return !isEmptyArray(conditions.get(AS_Q))// || !isEmptyArray(conditions.get(AS_EPQ))// @@ -81,22 +83,22 @@ public interface SearchRequestParams { || !isEmptyArray(conditions.get(AS_FILETYPE)); } - default boolean isEmptyArray(final String[] values) { + protected boolean isEmptyArray(final String[] values) { if (values == null || values.length == 0) { return true; } return stream(values).get(stream -> stream.allMatch(StringUtil::isBlank)); } - default String[] simplifyArray(final String[] values) { + protected String[] simplifyArray(final String[] values) { return stream(values).get(stream -> stream.filter(StringUtil::isNotBlank).distinct().toArray(n -> new String[n])); } - default String[] getParamValueArray(final HttpServletRequest request, final String param) { + protected String[] getParamValueArray(final HttpServletRequest request, final String param) { return simplifyArray(request.getParameterValues(param)); } - default FacetInfo createFacetInfo(final HttpServletRequest request) { + protected FacetInfo createFacetInfo(final HttpServletRequest request) { final String[] fields = getParamValueArray(request, "facet.field"); final String[] queries = getParamValueArray(request, "facet.query"); if (fields.length == 0 && queries.length == 0) { @@ -124,7 +126,7 @@ public interface SearchRequestParams { return facetInfo; } - default GeoInfo createGeoInfo(final HttpServletRequest request) { + protected GeoInfo createGeoInfo(final HttpServletRequest request) { return new GeoInfo(request); } diff --git a/src/main/java/org/codelibs/fess/es/client/FessEsClient.java b/src/main/java/org/codelibs/fess/es/client/FessEsClient.java index 32af1ecb6..b639ab166 100644 --- a/src/main/java/org/codelibs/fess/es/client/FessEsClient.java +++ b/src/main/java/org/codelibs/fess/es/client/FessEsClient.java @@ -51,6 +51,7 @@ import org.codelibs.elasticsearch.runner.ElasticsearchClusterRunner.Configs; import org.codelibs.fess.Constants; import org.codelibs.fess.entity.FacetInfo; import org.codelibs.fess.entity.GeoInfo; +import org.codelibs.fess.entity.HighlightInfo; import org.codelibs.fess.entity.PingResponse; import org.codelibs.fess.entity.QueryContext; import org.codelibs.fess.entity.SearchRequestParams.SearchRequestType; @@ -942,6 +943,7 @@ public class FessEsClient implements Client { private int size = Constants.DEFAULT_PAGE_SIZE; private GeoInfo geoInfo; private FacetInfo facetInfo; + private HighlightInfo highlightInfo; private String similarDocHash; private SearchRequestType searchRequestType = SearchRequestType.SEARCH; private boolean isScroll = false; @@ -960,8 +962,9 @@ public class FessEsClient implements Client { params.put("responseFields", responseFields); params.put("offset", offset); params.put("size", size); - // params.put("geoInfo", geoInfo); - // params.put("facetInfo", facetInfo); + // TODO support rescorer(convert to map) + // params.put("geoInfo", geoInfo); + // params.put("facetInfo", facetInfo); params.put("similarDocHash", similarDocHash); return params; } @@ -996,6 +999,11 @@ public class FessEsClient implements Client { return this; } + public SearchConditionBuilder highlightInfo(final HighlightInfo highlightInfo) { + this.highlightInfo = highlightInfo; + return this; + } + public SearchConditionBuilder similarDocHash(final String similarDocHash) { if (StringUtil.isNotBlank(similarDocHash)) { this.similarDocHash = similarDocHash; @@ -1059,8 +1067,8 @@ public class FessEsClient implements Client { // highlighting final HighlightBuilder highlightBuilder = new HighlightBuilder(); queryHelper.highlightedFields(stream -> stream.forEach(hf -> highlightBuilder.field(new HighlightBuilder.Field(hf) - .highlighterType(fessConfig.getQueryHighlightType()).fragmentSize(fessConfig.getQueryHighlightFragmentSizeAsInteger()) - .numOfFragments(fessConfig.getQueryHighlightNumberOfFragmentsAsInteger())))); + .highlighterType(highlightInfo.getType()).fragmentSize(highlightInfo.getFragmentSize()) + .numOfFragments(highlightInfo.getNumOfFragments())))); searchRequestBuilder.highlighter(highlightBuilder); // facets diff --git a/src/main/java/org/codelibs/fess/helper/ViewHelper.java b/src/main/java/org/codelibs/fess/helper/ViewHelper.java index c5f7351d5..0639aef7c 100644 --- a/src/main/java/org/codelibs/fess/helper/ViewHelper.java +++ b/src/main/java/org/codelibs/fess/helper/ViewHelper.java @@ -39,6 +39,7 @@ import java.util.stream.Collectors; import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; import org.apache.catalina.connector.ClientAbortException; import org.apache.commons.lang3.StringUtils; @@ -54,6 +55,7 @@ import org.codelibs.fess.crawler.client.CrawlerClientFactory; import org.codelibs.fess.crawler.entity.ResponseData; import org.codelibs.fess.crawler.util.CharUtil; import org.codelibs.fess.entity.FacetQueryView; +import org.codelibs.fess.entity.HighlightInfo; import org.codelibs.fess.es.config.exentity.CrawlingConfig; import org.codelibs.fess.exception.FessSystemException; import org.codelibs.fess.helper.UserAgentHelper.UserAgentType; @@ -82,6 +84,10 @@ public class ViewHelper { private static final Logger logger = LoggerFactory.getLogger(ViewHelper.class); + protected static final String SCREEN_WIDTH = "screen_width"; + + protected static final int TABLET_WIDTH = 768; + protected static final String CONTENT_DISPOSITION = "Content-Disposition"; protected static final String HL_CACHE = "hl_cache"; @@ -210,6 +216,40 @@ public class ViewHelper { return str.replaceAll(originalHighlightTagPre, StringUtil.EMPTY).replaceAll(originalHighlightTagPost, StringUtil.EMPTY); } + public HighlightInfo createHighlightInfo() { + return LaRequestUtil.getOptionalRequest().map(req -> { + final HighlightInfo highlightInfo = new HighlightInfo(); + final String widthStr = req.getParameter(SCREEN_WIDTH); + if (StringUtil.isNotBlank(widthStr)) { + final int width = Integer.parseInt(widthStr); + updateHighlisthInfo(highlightInfo, width); + final HttpSession session = req.getSession(false); + if (session != null) { + session.setAttribute(SCREEN_WIDTH, width); + } + } else { + final HttpSession session = req.getSession(false); + if (session != null) { + final Integer width = (Integer) session.getAttribute(SCREEN_WIDTH); + if (width != null) { + updateHighlisthInfo(highlightInfo, width); + } + } + } + return highlightInfo; + }).orElse(new HighlightInfo()); + } + + protected void updateHighlisthInfo(final HighlightInfo highlightInfo, final int width) { + if (width < TABLET_WIDTH) { + float ratio = ((float) width) / ((float) TABLET_WIDTH); + if (ratio < 0.5) { + ratio = 0.5f; + } + highlightInfo.fragmentSize((int) (highlightInfo.getFragmentSize() * ratio)); + } + } + public String getUrlLink(final Map document) { final FessConfig fessConfig = ComponentUtil.getFessConfig(); String url = DocumentUtil.getValue(document, fessConfig.getIndexFieldUrl(), String.class); diff --git a/src/test/java/org/codelibs/fess/util/QueryStringBuilderTest.java b/src/test/java/org/codelibs/fess/util/QueryStringBuilderTest.java index ef91b0137..7fcc1613d 100644 --- a/src/test/java/org/codelibs/fess/util/QueryStringBuilderTest.java +++ b/src/test/java/org/codelibs/fess/util/QueryStringBuilderTest.java @@ -21,6 +21,7 @@ import java.util.Map; import org.codelibs.fess.entity.FacetInfo; import org.codelibs.fess.entity.GeoInfo; +import org.codelibs.fess.entity.HighlightInfo; import org.codelibs.fess.entity.SearchRequestParams; import org.codelibs.fess.unit.UnitFessTestCase; @@ -150,6 +151,11 @@ public class QueryStringBuilderTest extends UnitFessTestCase { return null; } + @Override + public HighlightInfo getHighlightInfo() { + return new HighlightInfo(); + } + }).build(); } }