This is a cache of https://fess.codelibs.org/11.3/xref/org/codelibs/fess/util/QueryResponseList.html. It is a snapshot of the page at 2019-06-15T15:54:26.567+0000.
QueryResponseList xref
View Javadoc
1   /*
2    * Copyright 2012-2017 CodeLibs Project and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.codelibs.fess.util;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.HashMap;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.ListIterator;
24  import java.util.Map;
25  
26  import org.apache.commons.lang3.StringUtils;
27  import org.codelibs.core.stream.StreamUtil;
28  import org.codelibs.fess.helper.QueryHelper;
29  import org.codelibs.fess.helper.ViewHelper;
30  import org.codelibs.fess.mylasta.direction.fessConfig;
31  import org.dbflute.optional.OptionalEntity;
32  import org.elasticsearch.action.search.SearchResponse;
33  import org.elasticsearch.common.text.Text;
34  import org.elasticsearch.search.SearchHit;
35  import org.elasticsearch.search.SearchHitField;
36  import org.elasticsearch.search.SearchHits;
37  import org.elasticsearch.search.aggregations.Aggregations;
38  import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
39  import org.slf4j.Logger;
40  import org.slf4j.LoggerFactory;
41  
42  public class QueryResponseList implements List<Map<String, Object>> {
43  
44      private static final String SCORE = "score";
45  
46      private static final Logger logger = LoggerFactory.getLogger(QueryResponseList.class);
47  
48      private final List<Map<String, Object>> parent;
49  
50      /** The value of current page number. */
51      protected int pageSize;
52  
53      /** The value of current page number. */
54      protected int currentPageNumber;
55  
56      protected long allRecordCount;
57  
58      protected int allPageCount;
59  
60      protected boolean existNextPage;
61  
62      protected boolean existPrevPage;
63  
64      protected long currentStartRecordNumber;
65  
66      protected long currentEndRecordNumber;
67  
68      protected List<String> pageNumberList;
69  
70      protected String searchQuery;
71  
72      protected long execTime;
73  
74      protected FacetResponse facetResponse;
75  
76      protected boolean partialResults = false;
77  
78      protected long queryTime;
79  
80      public QueryResponseList() {
81          parent = new ArrayList<>();
82      }
83  
84      // for testing
85      protected QueryResponseList(final List<Map<String, Object>> parent) {
86          this.parent = parent;
87      }
88  
89      public void init(final OptionalEntity<SearchResponse> searchResponseOpt, final int start, final int pageSize) {
90          searchResponseOpt.ifPresent(searchResponse -> {
91              final fessConfig fessConfig = ComponentUtil.getfessConfig();
92              final SearchHits searchHits = searchResponse.getHits();
93              allRecordCount = searchHits.getTotalHits();
94              queryTime = searchResponse.getTookInMillis();
95  
96              if (searchResponse.getTotalShards() != searchResponse.getSuccessfulShards()) {
97                  partialResults = true;
98              }
99  
100             // build highlighting fields
101                 final QueryHelper queryHelper = ComponentUtil.getQueryHelper();
102                 final String hlPrefix = queryHelper.getHighlightPrefix();
103                 for (final SearchHit searchHit : searchHits.getHits()) {
104                     final Map<String, Object> docMap = parseSearchHit(fessConfig, hlPrefix, searchHit);
105 
106                     if (fessConfig.isResultCollapsed()) {
107                         final Map<String, SearchHits> innerHits = searchHit.getInnerHits();
108                         if (innerHits != null) {
109                             final SearchHits innerSearchHits = innerHits.get(fessConfig.getQueryCollapseInnerHitsName());
110                             if (innerSearchHits != null) {
111                                 final long totalHits = innerSearchHits.getTotalHits();
112                                 if (totalHits > 1) {
113                                     docMap.put(fessConfig.getQueryCollapseInnerHitsName() + "_count", totalHits);
114                                     final SearchHitField bitsField =
115                                             searchHit.getFields().get(fessConfig.getIndexFieldContentMinhashBits());
116                                     if (bitsField != null && !bitsField.getValues().isEmpty()) {
117                                         docMap.put(fessConfig.getQueryCollapseInnerHitsName() + "_hash", bitsField.getValues().get(0));
118                                     }
119                                     docMap.put(
120                                             fessConfig.getQueryCollapseInnerHitsName(),
121                                             StreamUtil.stream(innerSearchHits.getHits()).get(
122                                                     stream -> stream.map(v -> parseSearchHit(fessConfig, hlPrefix, v)).toArray(
123                                                             n -> new Map[n])));
124                                 }
125                             }
126                         }
127                     }
128 
129                     parent.add(docMap);
130                 }
131 
132                 // facet
133                 final Aggregations aggregations = searchResponse.getAggregations();
134                 if (aggregations != null) {
135                     facetResponse = new FacetResponse(aggregations);
136                 }
137 
138             });
139 
140         calculatePageInfo(start, pageSize);
141     }
142 
143     private Map<String, Object> parseSearchHit(final fessConfig fessConfig, final String hlPrefix, final SearchHit searchHit) {
144         final Map<String, Object> docMap = new HashMap<>();
145         if (searchHit.getSource() == null) {
146             searchHit.getFields().forEach((key, value) -> {
147                 docMap.put(key, value.getValue());
148             });
149         } else {
150             docMap.putAll(searchHit.getSource());
151         }
152 
153         final Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
154         try {
155             if (highlightFields != null) {
156                 for (final Map.Entry<String, HighlightField> entry : highlightFields.entrySet()) {
157                     final HighlightField highlightField = entry.getValue();
158                     final Text[] fragments = highlightField.fragments();
159                     if (fragments != null && fragments.length != 0) {
160                         final String[] texts = new String[fragments.length];
161                         for (int i = 0; i < fragments.length; i++) {
162                             texts[i] = fragments[i].string();
163                         }
164                         final String value = StringUtils.join(texts, "...");
165                         docMap.put(hlPrefix + highlightField.getName(), value);
166                     }
167                 }
168             }
169         } catch (final Exception e) {
170             if (logger.isDebugEnabled()) {
171                 logger.debug("Could not create a highlighting value: " + docMap, e);
172             }
173         }
174 
175         // ContentTitle
176         final ViewHelper viewHelper = ComponentUtil.getViewHelper();
177         if (viewHelper != null) {
178             docMap.put(fessConfig.getResponseFieldContentTitle(), viewHelper.getContentTitle(docMap));
179             docMap.put(fessConfig.getResponseFieldContentDescription(), viewHelper.getContentDescription(docMap));
180             docMap.put(fessConfig.getResponseFieldUrlLink(), viewHelper.getUrlLink(docMap));
181             docMap.put(fessConfig.getResponseFieldSitePath(), viewHelper.getSitePath(docMap));
182         }
183 
184         if (!docMap.containsKey(SCORE)) {
185             docMap.put(SCORE, searchHit.getScore());
186         }
187         return docMap;
188     }
189 
190     protected void calculatePageInfo(final int start, final int size) {
191         pageSize = size;
192         allPageCount = (int) ((allRecordCount - 1) / pageSize) + 1;
193         existPrevPage = start > 0;
194         existNextPage = start < (long) (allPageCount - 1) * (long) pageSize;
195         currentPageNumber = start / pageSize + 1;
196         if (existNextPage && size() < pageSize) {
197             // collapsing
198             existNextPage = false;
199             allPageCount = currentPageNumber;
200         }
201         currentStartRecordNumber = allRecordCount != 0 ? (currentPageNumber - 1) * pageSize + 1 : 0;
202         currentEndRecordNumber = (long) currentPageNumber * pageSize;
203         currentEndRecordNumber = allRecordCount < currentEndRecordNumber ? allRecordCount : currentEndRecordNumber;
204 
205         final int pageRangeSize = 5;
206         int startPageRangeSize = currentPageNumber - pageRangeSize;
207         if (startPageRangeSize < 1) {
208             startPageRangeSize = 1;
209         }
210         int endPageRangeSize = currentPageNumber + pageRangeSize;
211         if (endPageRangeSize > allPageCount) {
212             endPageRangeSize = allPageCount;
213         }
214         pageNumberList = new ArrayList<>();
215         for (int i = startPageRangeSize; i <= endPageRangeSize; i++) {
216             pageNumberList.add(String.valueOf(i));
217         }
218     }
219 
220     @Override
221     public boolean add(final Map<String, Object> e) {
222         return parent.add(e);
223     }
224 
225     @Override
226     public void add(final int index, final Map<String, Object> element) {
227         parent.add(index, element);
228     }
229 
230     @Override
231     public boolean addAll(final Collection<? extends Map<String, Object>> c) {
232         return parent.addAll(c);
233     }
234 
235     @Override
236     public boolean addAll(final int index, final Collection<? extends Map<String, Object>> c) {
237         return parent.addAll(index, c);
238     }
239 
240     @Override
241     public void clear() {
242         parent.clear();
243     }
244 
245     @Override
246     public boolean contains(final Object o) {
247         return parent.contains(o);
248     }
249 
250     @Override
251     public boolean containsAll(final Collection<?> c) {
252         return parent.containsAll(c);
253     }
254 
255     @Override
256     public boolean equals(final Object o) {
257         return parent.equals(o);
258     }
259 
260     @Override
261     public Map<String, Object> get(final int index) {
262         return parent.get(index);
263     }
264 
265     @Override
266     public int hashCode() {
267         return parent.hashCode();
268     }
269 
270     @Override
271     public int indexOf(final Object o) {
272         return parent.indexOf(o);
273     }
274 
275     @Override
276     public boolean isEmpty() {
277         return parent.isEmpty();
278     }
279 
280     @Override
281     public Iterator<Map<String, Object>> iterator() {
282         return parent.iterator();
283     }
284 
285     @Override
286     public int lastIndexOf(final Object o) {
287         return parent.lastIndexOf(o);
288     }
289 
290     @Override
291     public ListIterator<Map<String, Object>> listIterator() {
292         return parent.listIterator();
293     }
294 
295     @Override
296     public ListIterator<Map<String, Object>> listIterator(final int index) {
297         return parent.listIterator(index);
298     }
299 
300     @Override
301     public Map<String, Object> remove(final int index) {
302         return parent.remove(index);
303     }
304 
305     @Override
306     public boolean remove(final Object o) {
307         return parent.remove(o);
308     }
309 
310     @Override
311     public boolean removeAll(final Collection<?> c) {
312         return parent.removeAll(c);
313     }
314 
315     @Override
316     public boolean retainAll(final Collection<?> c) {
317         return parent.retainAll(c);
318     }
319 
320     @Override
321     public Map<String, Object> set(final int index, final Map<String, Object> element) {
322         return parent.set(index, element);
323     }
324 
325     @Override
326     public int size() {
327         return parent.size();
328     }
329 
330     @Override
331     public List<Map<String, Object>> subList(final int fromIndex, final int toIndex) {
332         return parent.subList(fromIndex, toIndex);
333     }
334 
335     @Override
336     public Object[] toArray() {
337         return parent.toArray();
338     }
339 
340     @Override
341     public <T> T[] toArray(final T[] a) {
342         return parent.toArray(a);
343     }
344 
345     public int getPageSize() {
346         return pageSize;
347     }
348 
349     public int getCurrentPageNumber() {
350         return currentPageNumber;
351     }
352 
353     public long getAllRecordCount() {
354         return allRecordCount;
355     }
356 
357     public int getAllPageCount() {
358         return allPageCount;
359     }
360 
361     public boolean isExistNextPage() {
362         return existNextPage;
363     }
364 
365     public boolean isExistPrevPage() {
366         return existPrevPage;
367     }
368 
369     public long getCurrentStartRecordNumber() {
370         return currentStartRecordNumber;
371     }
372 
373     public long getCurrentEndRecordNumber() {
374         return currentEndRecordNumber;
375     }
376 
377     public List<String> getPageNumberList() {
378         return pageNumberList;
379     }
380 
381     public String getSearchQuery() {
382         return searchQuery;
383     }
384 
385     public void setSearchQuery(final String searchQuery) {
386         this.searchQuery = searchQuery;
387     }
388 
389     public long getExecTime() {
390         return execTime;
391     }
392 
393     public void setExecTime(final long execTime) {
394         this.execTime = execTime;
395     }
396 
397     public FacetResponse getFacetResponse() {
398         return facetResponse;
399     }
400 
401     public boolean isPartialResults() {
402         return partialResults;
403     }
404 
405     public long getQueryTime() {
406         return queryTime;
407     }
408 
409 }