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