Java tutorial
/* * 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.util; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.codelibs.core.lang.StringUtil; import org.codelibs.core.stream.StreamUtil; import org.codelibs.fess.Constants; import org.codelibs.fess.helper.QueryHelper; import org.codelibs.fess.helper.ViewHelper; import org.codelibs.fess.mylasta.direction.FessConfig; import org.dbflute.optional.OptionalEntity; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.common.document.DocumentField; import org.elasticsearch.common.text.Text; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.aggregations.Aggregations; import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class QueryResponseList implements List<Map<String, Object>> { private static final Logger logger = LoggerFactory.getLogger(QueryResponseList.class); protected static final String ELLIPSIS = "..."; protected final List<Map<String, Object>> parent; /** The value of current page number. */ protected int pageSize; /** The value of current page number. */ protected int currentPageNumber; protected long allRecordCount; protected int allPageCount; protected boolean existNextPage; protected boolean existPrevPage; protected long currentStartRecordNumber; protected long currentEndRecordNumber; protected List<String> pageNumberList; protected String searchQuery; protected long execTime; protected FacetResponse facetResponse; protected boolean partialResults = false; protected long queryTime; public QueryResponseList() { parent = new ArrayList<>(); } // for testing protected QueryResponseList(final List<Map<String, Object>> parent) { this.parent = parent; } public void init(final OptionalEntity<SearchResponse> searchResponseOpt, final int start, final int pageSize) { searchResponseOpt.ifPresent(searchResponse -> { final FessConfig fessConfig = ComponentUtil.getFessConfig(); final SearchHits searchHits = searchResponse.getHits(); allRecordCount = searchHits.getTotalHits().value; queryTime = searchResponse.getTook().millis(); if (searchResponse.getTotalShards() != searchResponse.getSuccessfulShards()) { partialResults = true; } // build highlighting fields final QueryHelper queryHelper = ComponentUtil.getQueryHelper(); final String hlPrefix = queryHelper.getHighlightPrefix(); for (final SearchHit searchHit : searchHits.getHits()) { final Map<String, Object> docMap = parseSearchHit(fessConfig, hlPrefix, searchHit); if (fessConfig.isResultCollapsed()) { final Map<String, SearchHits> innerHits = searchHit.getInnerHits(); if (innerHits != null) { final SearchHits innerSearchHits = innerHits .get(fessConfig.getQueryCollapseInnerHitsName()); if (innerSearchHits != null) { final long totalHits = innerSearchHits.getTotalHits().value; if (totalHits > 1) { docMap.put(fessConfig.getQueryCollapseInnerHitsName() + "_count", totalHits); final DocumentField bitsField = searchHit.getFields() .get(fessConfig.getIndexFieldContentMinhashBits()); if (bitsField != null && !bitsField.getValues().isEmpty()) { docMap.put(fessConfig.getQueryCollapseInnerHitsName() + "_hash", bitsField.getValues().get(0)); } docMap.put(fessConfig.getQueryCollapseInnerHitsName(), StreamUtil.stream(innerSearchHits.getHits()) .get(stream -> stream .map(v -> parseSearchHit(fessConfig, hlPrefix, v)) .toArray(n -> new Map[n]))); } } } } parent.add(docMap); } // facet final Aggregations aggregations = searchResponse.getAggregations(); if (aggregations != null) { facetResponse = new FacetResponse(aggregations); } }); calculatePageInfo(start, pageSize); } protected Map<String, Object> parseSearchHit(final FessConfig fessConfig, final String hlPrefix, final SearchHit searchHit) { final Map<String, Object> docMap = new HashMap<>(32); if (searchHit.getSourceAsMap() == null) { searchHit.getFields().forEach((key, value) -> { docMap.put(key, value.getValue()); }); } else { docMap.putAll(searchHit.getSourceAsMap()); } final Map<String, HighlightField> highlightFields = searchHit.getHighlightFields(); try { if (highlightFields != null) { for (final Map.Entry<String, HighlightField> entry : highlightFields.entrySet()) { final HighlightField highlightField = entry.getValue(); final Text[] fragments = highlightField.fragments(); if (fragments != null && fragments.length != 0) { final String[] texts = new String[fragments.length]; for (int i = 0; i < fragments.length; i++) { texts[i] = fragments[i].string(); } String value = StringUtils.join(texts, ELLIPSIS); if (StringUtil.isNotBlank(value) && !fessConfig.endsWithFullstop(value)) { value = value + ELLIPSIS; } docMap.put(hlPrefix + highlightField.getName(), value); } } } } catch (final Exception e) { if (logger.isDebugEnabled()) { logger.debug("Could not create a highlighting value: " + docMap, e); } } // ContentTitle final ViewHelper viewHelper = ComponentUtil.getViewHelper(); if (viewHelper != null) { docMap.put(fessConfig.getResponseFieldContentTitle(), viewHelper.getContentTitle(docMap)); docMap.put(fessConfig.getResponseFieldContentDescription(), viewHelper.getContentDescription(docMap)); docMap.put(fessConfig.getResponseFieldUrlLink(), viewHelper.getUrlLink(docMap)); docMap.put(fessConfig.getResponseFieldSitePath(), viewHelper.getSitePath(docMap)); } if (!docMap.containsKey(Constants.SCORE)) { docMap.put(Constants.SCORE, searchHit.getScore()); } if (!docMap.containsKey(fessConfig.getIndexFieldId())) { docMap.put(fessConfig.getIndexFieldId(), searchHit.getId()); } return docMap; } protected void calculatePageInfo(final int start, final int size) { pageSize = size; allPageCount = (int) ((allRecordCount - 1) / pageSize) + 1; existPrevPage = start > 0; existNextPage = start < (long) (allPageCount - 1) * (long) pageSize; currentPageNumber = start / pageSize + 1; if (existNextPage && size() < pageSize) { // collapsing existNextPage = false; allPageCount = currentPageNumber; } currentStartRecordNumber = allRecordCount != 0 ? start + 1 : 0; currentEndRecordNumber = currentStartRecordNumber + pageSize - 1; currentEndRecordNumber = allRecordCount < currentEndRecordNumber ? allRecordCount : currentEndRecordNumber; final int pageRangeSize = 5; int startPageRangeSize = currentPageNumber - pageRangeSize; if (startPageRangeSize < 1) { startPageRangeSize = 1; } int endPageRangeSize = currentPageNumber + pageRangeSize; if (endPageRangeSize > allPageCount) { endPageRangeSize = allPageCount; } pageNumberList = new ArrayList<>(); for (int i = startPageRangeSize; i <= endPageRangeSize; i++) { pageNumberList.add(String.valueOf(i)); } } @Override public boolean add(final Map<String, Object> e) { return parent.add(e); } @Override public void add(final int index, final Map<String, Object> element) { parent.add(index, element); } @Override public boolean addAll(final Collection<? extends Map<String, Object>> c) { return parent.addAll(c); } @Override public boolean addAll(final int index, final Collection<? extends Map<String, Object>> c) { return parent.addAll(index, c); } @Override public void clear() { parent.clear(); } @Override public boolean contains(final Object o) { return parent.contains(o); } @Override public boolean containsAll(final Collection<?> c) { return parent.containsAll(c); } @Override public boolean equals(final Object o) { return parent.equals(o); } @Override public Map<String, Object> get(final int index) { return parent.get(index); } @Override public int hashCode() { return parent.hashCode(); } @Override public int indexOf(final Object o) { return parent.indexOf(o); } @Override public boolean isEmpty() { return parent.isEmpty(); } @Override public Iterator<Map<String, Object>> iterator() { return parent.iterator(); } @Override public int lastIndexOf(final Object o) { return parent.lastIndexOf(o); } @Override public ListIterator<Map<String, Object>> listIterator() { return parent.listIterator(); } @Override public ListIterator<Map<String, Object>> listIterator(final int index) { return parent.listIterator(index); } @Override public Map<String, Object> remove(final int index) { return parent.remove(index); } @Override public boolean remove(final Object o) { return parent.remove(o); } @Override public boolean removeAll(final Collection<?> c) { return parent.removeAll(c); } @Override public boolean retainAll(final Collection<?> c) { return parent.retainAll(c); } @Override public Map<String, Object> set(final int index, final Map<String, Object> element) { return parent.set(index, element); } @Override public int size() { return parent.size(); } @Override public List<Map<String, Object>> subList(final int fromIndex, final int toIndex) { return parent.subList(fromIndex, toIndex); } @Override public Object[] toArray() { return parent.toArray(); } @Override public <T> T[] toArray(final T[] a) { return parent.toArray(a); } public int getPageSize() { return pageSize; } public int getCurrentPageNumber() { return currentPageNumber; } public long getAllRecordCount() { return allRecordCount; } public int getAllPageCount() { return allPageCount; } public boolean isExistNextPage() { return existNextPage; } public boolean isExistPrevPage() { return existPrevPage; } public long getCurrentStartRecordNumber() { return currentStartRecordNumber; } public long getCurrentEndRecordNumber() { return currentEndRecordNumber; } public List<String> getPageNumberList() { return pageNumberList; } public String getSearchQuery() { return searchQuery; } public void setSearchQuery(final String searchQuery) { this.searchQuery = searchQuery; } public long getExecTime() { return execTime; } public void setExecTime(final long execTime) { this.execTime = execTime; } public FacetResponse getFacetResponse() { return facetResponse; } public boolean isPartialResults() { return partialResults; } public long getQueryTime() { return queryTime; } }