|
15 | 15 | */
|
16 | 16 | package org.codelibs.fess.webapp.semantic_search.rank.fusion;
|
17 | 17 |
|
| 18 | +import static org.codelibs.fess.webapp.semantic_search.SemanticSearchConstants.CONTENT_CHUNK_FIELD; |
| 19 | +import static org.codelibs.fess.webapp.semantic_search.SemanticSearchConstants.CONTENT_NESTED_FIELD; |
| 20 | + |
| 21 | +import java.util.ArrayList; |
| 22 | +import java.util.Arrays; |
| 23 | +import java.util.List; |
18 | 24 | import java.util.Locale;
|
19 | 25 | import java.util.Map;
|
| 26 | +import java.util.stream.Stream; |
20 | 27 |
|
21 | 28 | import javax.annotation.PostConstruct;
|
22 | 29 |
|
23 | 30 | import org.apache.logging.log4j.LogManager;
|
24 | 31 | import org.apache.logging.log4j.Logger;
|
| 32 | +import org.codelibs.core.lang.StringUtil; |
25 | 33 | import org.codelibs.fess.entity.FacetInfo;
|
26 | 34 | import org.codelibs.fess.entity.GeoInfo;
|
27 | 35 | import org.codelibs.fess.entity.HighlightInfo;
|
28 | 36 | import org.codelibs.fess.entity.SearchRequestParams;
|
| 37 | +import org.codelibs.fess.es.client.SearchEngineClient.SearchCondition; |
| 38 | +import org.codelibs.fess.es.client.SearchEngineClient.SearchConditionBuilder; |
29 | 39 | import org.codelibs.fess.mylasta.action.FessUserBean;
|
| 40 | +import org.codelibs.fess.mylasta.direction.FessConfig; |
30 | 41 | import org.codelibs.fess.rank.fusion.DefaultSearcher;
|
31 | 42 | import org.codelibs.fess.rank.fusion.SearchResult;
|
32 | 43 | import org.codelibs.fess.util.ComponentUtil;
|
| 44 | +import org.codelibs.fess.util.DocumentUtil; |
33 | 45 | import org.codelibs.fess.webapp.semantic_search.SemanticSearchConstants;
|
34 | 46 | import org.codelibs.fess.webapp.semantic_search.helper.SemanticSearchHelper;
|
35 | 47 | import org.dbflute.optional.OptionalThing;
|
| 48 | +import org.opensearch.action.search.SearchRequestBuilder; |
| 49 | +import org.opensearch.search.SearchHit; |
| 50 | +import org.opensearch.search.SearchHit.NestedIdentity; |
| 51 | +import org.opensearch.search.SearchHits; |
36 | 52 |
|
37 | 53 | public class SemanticSearcher extends DefaultSearcher {
|
38 | 54 | private static final Logger logger = LogManager.getLogger(SemanticSearcher.class);
|
@@ -74,6 +90,72 @@ protected SearchResult search(final String query, final SearchRequestParams para
|
74 | 90 | }
|
75 | 91 | }
|
76 | 92 |
|
| 93 | + @Override |
| 94 | + protected SearchCondition<SearchRequestBuilder> createSearchCondition(final String query, final SearchRequestParams params, |
| 95 | + final OptionalThing<FessUserBean> userBean) { |
| 96 | + final String chunkField = System.getProperty(CONTENT_CHUNK_FIELD); // ex. content_chunk |
| 97 | + if (StringUtil.isBlank(chunkField)) { |
| 98 | + return super.createSearchCondition(query, params, userBean); |
| 99 | + } |
| 100 | + final String[] responseFields = |
| 101 | + Stream.concat(Arrays.stream(params.getResponseFields()), Stream.of(chunkField)).toArray(String[]::new); |
| 102 | + if (logger.isDebugEnabled()) { |
| 103 | + logger.debug("responseFields={}", Arrays.toString(responseFields)); |
| 104 | + } |
| 105 | + return searchRequestBuilder -> { |
| 106 | + ComponentUtil.getQueryHelper().processSearchPreference(searchRequestBuilder, userBean, query); |
| 107 | + return SearchConditionBuilder.builder(searchRequestBuilder).query(query).offset(params.getStartPosition()) |
| 108 | + .size(params.getPageSize()).facetInfo(params.getFacetInfo()).geoInfo(params.getGeoInfo()) |
| 109 | + .highlightInfo(params.getHighlightInfo()).similarDocHash(params.getSimilarDocHash()).responseFields(responseFields) |
| 110 | + .searchRequestType(params.getType()).trackTotalHits(params.getTrackTotalHits()).minScore(params.getMinScore()).build(); |
| 111 | + }; |
| 112 | + } |
| 113 | + |
| 114 | + @Override |
| 115 | + protected Map<String, Object> parseSearchHit(final FessConfig fessConfig, final String hlPrefix, final SearchHit searchHit) { |
| 116 | + final Map<String, Object> docMap = super.parseSearchHit(fessConfig, hlPrefix, searchHit); |
| 117 | + final Map<String, SearchHits> innerHits = searchHit.getInnerHits(); |
| 118 | + if (innerHits != null) { |
| 119 | + final String chunkField = System.getProperty(CONTENT_CHUNK_FIELD); // ex. content_chunk |
| 120 | + if (StringUtil.isNotBlank(chunkField)) { |
| 121 | + final String nestedField = System.getProperty(CONTENT_NESTED_FIELD); // ex. content_vector |
| 122 | + final SearchHits innerSearchHits = innerHits.get(nestedField); |
| 123 | + if (logger.isDebugEnabled()) { |
| 124 | + logger.debug("nestedField={}, innerSearchHits={}", nestedField, innerSearchHits); |
| 125 | + } |
| 126 | + final String[] chunks = DocumentUtil.getValue(docMap, chunkField, String[].class); |
| 127 | + docMap.remove(chunkField); |
| 128 | + if (innerSearchHits != null) { |
| 129 | + final List<String> chunkList = new ArrayList<>(); |
| 130 | + String contentDesc = null; |
| 131 | + for (final SearchHit hit : innerSearchHits.getHits()) { |
| 132 | + final NestedIdentity nestedIdentity = hit.getNestedIdentity(); |
| 133 | + if (nestedIdentity != null) { |
| 134 | + final int offset = nestedIdentity.getOffset(); |
| 135 | + if (logger.isDebugEnabled()) { |
| 136 | + logger.debug("offset={}, chunks={}", offset, chunks); |
| 137 | + } |
| 138 | + if (chunks != null && chunks.length > offset) { |
| 139 | + if (contentDesc == null) { |
| 140 | + contentDesc = chunks[offset]; |
| 141 | + } |
| 142 | + chunkList.add(chunks[offset]); |
| 143 | + } |
| 144 | + } |
| 145 | + } |
| 146 | + if (StringUtil.isNotBlank(contentDesc)) { |
| 147 | + if (logger.isDebugEnabled()) { |
| 148 | + logger.debug("matched chunk: {}={}", fessConfig.getResponseFieldContentDescription(), contentDesc); |
| 149 | + } |
| 150 | + docMap.put(fessConfig.getResponseFieldContentDescription(), contentDesc); |
| 151 | + } |
| 152 | + docMap.put(chunkField, chunkList.toArray(n -> new String[n])); |
| 153 | + } |
| 154 | + } |
| 155 | + } |
| 156 | + return docMap; |
| 157 | + } |
| 158 | + |
77 | 159 | protected boolean isSearchableField(final String field) {
|
78 | 160 | for (final String f : ComponentUtil.getQueryFieldConfig().getSearchFields()) {
|
79 | 161 | if (field.equals(f)) {
|
|
0 commit comments