1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.query;
17
18 import static org.codelibs.core.stream.StreamUtil.stream;
19
20 import java.lang.Character.UnicodeBlock;
21
22 import org.apache.lucene.search.Query;
23 import org.codelibs.core.lang.StringUtil;
24 import org.codelibs.fess.Constants;
25 import org.codelibs.fess.entity.QueryContext;
26 import org.codelibs.fess.mylasta.direction.FessConfig;
27 import org.codelibs.fess.util.ComponentUtil;
28 import org.dbflute.optional.OptionalThing;
29 import org.lastaflute.web.util.LaRequestUtil;
30 import org.opensearch.index.query.BoolQueryBuilder;
31 import org.opensearch.index.query.DisMaxQueryBuilder;
32 import org.opensearch.index.query.QueryBuilder;
33 import org.opensearch.index.query.QueryBuilders;
34 import org.opensearch.search.sort.SortBuilder;
35 import org.opensearch.search.sort.SortBuilders;
36 import org.opensearch.search.sort.SortOrder;
37
38
39
40
41
42 public abstract class QueryCommand {
43
44
45
46
47
48 public QueryCommand() {
49
50 }
51
52
53
54
55
56
57
58
59 public abstract QueryBuilder execute(final QueryContext context, final Query query, final float boost);
60
61
62
63
64
65 protected abstract String getQueryClassName();
66
67
68
69
70
71 public void register() {
72 ComponentUtil.getQueryProcessor().add(getQueryClassName(), this);
73 }
74
75
76
77
78
79 protected QueryFieldConfig getQueryFieldConfig() {
80 return ComponentUtil.getQueryFieldConfig();
81 }
82
83
84
85
86
87 protected QueryProcessor getQueryProcessor() {
88 return ComponentUtil.getQueryProcessor();
89 }
90
91
92
93
94
95
96
97 protected SortBuilder<?> createFieldSortBuilder(final String field, final SortOrder order) {
98 if (QueryFieldConfig.SCORE_FIELD.equals(field) || QueryFieldConfig.DOC_SCORE_FIELD.equals(field)) {
99 return SortBuilders.scoreSort().order(order);
100 }
101 return SortBuilders.fieldSort(field).order(order);
102 }
103
104
105
106
107
108
109
110 protected boolean isSearchField(final String field) {
111 final QueryFieldConfig config = getQueryFieldConfig();
112 return config.searchFieldSet != null && config.searchFieldSet.contains(field);
113 }
114
115
116
117
118
119 protected OptionalThing<String[]> getQueryLanguages() {
120 return LaRequestUtil.getOptionalRequest()
121 .map(request -> ComponentUtil.getFessConfig()
122 .getQueryLanguages(request.getLocales(), (String[]) request.getAttribute(Constants.REQUEST_LANGUAGES)));
123 }
124
125
126
127
128
129
130
131
132 protected DefaultQueryBuilder buildDefaultQueryBuilder(final FessConfig fessConfig, final QueryContext context,
133 final DefaultQueryBuilderFunction builder) {
134 final DefaultQueryBuilder defaultQuery = createDefaultQueryBuilder();
135 defaultQuery.add(builder.apply(fessConfig.getIndexFieldTitle(), fessConfig.getQueryBoostTitleAsDecimal().floatValue()));
136 defaultQuery.add(builder.apply(fessConfig.getIndexFieldContent(), fessConfig.getQueryBoostContentAsDecimal().floatValue()));
137 final float importantContentBoost = fessConfig.getQueryBoostImportantContentAsDecimal().floatValue();
138 if (importantContentBoost >= 0.0f) {
139 defaultQuery.add(builder.apply(fessConfig.getIndexFieldImportantContent(), importantContentBoost));
140 }
141 final float importantContantLangBoost = fessConfig.getQueryBoostImportantContentLangAsDecimal().floatValue();
142 getQueryLanguages().ifPresent(langs -> stream(langs).of(stream -> stream.forEach(lang -> {
143 defaultQuery.add(
144 builder.apply(fessConfig.getIndexFieldTitle() + "_" + lang, fessConfig.getQueryBoostTitleLangAsDecimal().floatValue()));
145 defaultQuery.add(builder.apply(fessConfig.getIndexFieldContent() + "_" + lang,
146 fessConfig.getQueryBoostContentLangAsDecimal().floatValue()));
147 if (importantContantLangBoost >= 0.0f) {
148 defaultQuery.add(builder.apply(fessConfig.getIndexFieldImportantContent() + "_" + lang, importantContantLangBoost));
149 }
150 })));
151 getQueryFieldConfig().additionalDefaultList.stream().forEach(f -> {
152 final QueryBuilder query = builder.apply(f.getFirst(), f.getSecond());
153 defaultQuery.add(query);
154 });
155 return defaultQuery;
156 }
157
158
159
160
161
162 protected DefaultQueryBuilder createDefaultQueryBuilder() {
163 final FessConfig fessConfig = ComponentUtil.getFessConfig();
164
165 if ("dismax".equals(fessConfig.getQueryDefaultQueryType())) {
166 final DisMaxQueryBuilder disMaxQuery = QueryBuilders.disMaxQuery();
167 disMaxQuery.tieBreaker(fessConfig.getQueryDismaxTieBreakerAsDecimal().floatValue());
168 return new DefaultQueryBuilder(disMaxQuery);
169 }
170
171 final BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
172 final String minimumShouldMatch = fessConfig.getQueryBoolMinimumShouldMatch();
173 if (StringUtil.isNotBlank(minimumShouldMatch)) {
174 boolQuery.minimumShouldMatch(minimumShouldMatch);
175 }
176 return new DefaultQueryBuilder(boolQuery);
177 }
178
179
180
181
182
183
184
185
186 protected QueryBuilder buildMatchPhraseQuery(final String f, final String text) {
187 final FessConfig fessConfig = ComponentUtil.getFessConfig();
188 if (text == null || text.length() != 1
189 || !fessConfig.getIndexFieldTitle().equals(f) && !fessConfig.getIndexFieldContent().equals(f)) {
190 return QueryBuilders.matchPhraseQuery(f, text);
191 }
192
193 final UnicodeBlock block = UnicodeBlock.of(text.codePointAt(0));
194 if (block == UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
195 || block == UnicodeBlock.HIRAGANA
196 || block == UnicodeBlock.KATAKANA
197 || block == UnicodeBlock.HANGUL_SYLLABLES
198 ) {
199 return QueryBuilders.prefixQuery(f, text);
200 }
201 return QueryBuilders.matchPhraseQuery(f, text);
202 }
203
204
205
206
207
208
209
210 protected String getSearchField(final String defaultField, final String field) {
211 if (Constants.DEFAULT_FIELD.equals(field) && defaultField != null) {
212 return defaultField;
213 }
214 return field;
215 }
216
217
218
219
220 protected interface DefaultQueryBuilderFunction {
221
222
223
224
225
226
227 QueryBuilder apply(String field, float boost);
228 }
229
230
231
232
233 protected interface FieldQueryBuilder {
234
235
236
237
238
239
240
241 QueryBuilder buildQuery(String field, String text, float boost);
242 }
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261 protected QueryBuilder convertWithFieldCheck(final FessConfig fessConfig, final QueryContext context, final String field,
262 final String text, final float boost, final DefaultQueryBuilderFunction defaultBuilder, final FieldQueryBuilder fieldBuilder) {
263
264 context.addFieldLog(field, text);
265 context.addHighlightedQuery(text);
266
267 if (Constants.DEFAULT_FIELD.equals(field)) {
268 return buildDefaultQueryBuilder(fessConfig, context, defaultBuilder);
269 }
270
271 if (isSearchField(field)) {
272 return fieldBuilder.buildQuery(field, text, boost);
273 }
274
275
276 context.addFieldLog(Constants.DEFAULT_FIELD, text);
277 return buildDefaultQueryBuilder(fessConfig, context, defaultBuilder);
278 }
279 }