1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.app.service;
17
18 import java.nio.charset.StandardCharsets;
19 import java.time.LocalDateTime;
20 import java.time.ZoneId;
21 import java.time.ZoneOffset;
22 import java.time.format.DateTimeFormatter;
23 import java.util.Base64;
24 import java.util.HashMap;
25 import java.util.LinkedHashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.stream.Collectors;
29
30 import org.apache.logging.log4j.LogManager;
31 import org.apache.logging.log4j.Logger;
32 import org.codelibs.core.beans.util.BeanUtil;
33 import org.codelibs.core.lang.StringUtil;
34 import org.codelibs.fess.Constants;
35 import org.codelibs.fess.app.pager.SearchLogPager;
36 import org.codelibs.fess.exception.FessSystemException;
37 import org.codelibs.fess.helper.SystemHelper;
38 import org.codelibs.fess.mylasta.direction.FessConfig;
39 import org.codelibs.fess.opensearch.log.allcommon.EsPagingResultBean;
40 import org.codelibs.fess.opensearch.log.cbean.ClickLogCB;
41 import org.codelibs.fess.opensearch.log.cbean.FavoriteLogCB;
42 import org.codelibs.fess.opensearch.log.cbean.SearchLogCB;
43 import org.codelibs.fess.opensearch.log.cbean.UserInfoCB;
44 import org.codelibs.fess.opensearch.log.exbhv.ClickLogBhv;
45 import org.codelibs.fess.opensearch.log.exbhv.FavoriteLogBhv;
46 import org.codelibs.fess.opensearch.log.exbhv.SearchLogBhv;
47 import org.codelibs.fess.opensearch.log.exbhv.UserInfoBhv;
48 import org.codelibs.fess.opensearch.log.exentity.ClickLog;
49 import org.codelibs.fess.opensearch.log.exentity.FavoriteLog;
50 import org.codelibs.fess.opensearch.log.exentity.SearchLog;
51 import org.codelibs.fess.opensearch.log.exentity.UserInfo;
52 import org.codelibs.fess.taglib.FessFunctions;
53 import org.dbflute.optional.OptionalEntity;
54 import org.opensearch.search.aggregations.AggregationBuilders;
55 import org.opensearch.search.aggregations.BucketOrder;
56 import org.opensearch.search.aggregations.bucket.histogram.DateHistogramInterval;
57 import org.opensearch.search.aggregations.bucket.histogram.Histogram;
58 import org.opensearch.search.aggregations.bucket.terms.Terms;
59 import org.opensearch.search.aggregations.metrics.Avg;
60 import org.opensearch.search.aggregations.metrics.Cardinality;
61
62 import jakarta.annotation.Resource;
63
64
65
66
67
68
69
70
71
72 public class SearchLogService {
73
74
75 private static final String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
76
77
78 private static final String COUNT = "count";
79
80
81 private static final String KEY = "key";
82
83
84 private static final String ID = "id";
85
86
87 private static final String USER_INFO_ID = "userInfoId";
88
89
90 private static final String QUERY_TIME = "queryTime";
91
92
93 private static final Logger logger = LogManager.getLogger(SearchLogService.class);
94
95
96 @Resource
97 private SearchLogBhv searchLogBhv;
98
99
100 @Resource
101 private ClickLogBhv clickLogBhv;
102
103
104 @Resource
105 private FavoriteLogBhv favoriteLogBhv;
106
107
108 @Resource
109 private UserInfoBhv userInfoBhv;
110
111
112 @Resource
113 private SystemHelper systemHelper;
114
115
116 @Resource
117 protected FessConfig fessConfig;
118
119
120
121
122 public SearchLogService() {
123
124 }
125
126
127
128
129
130
131 public void deleteBefore(final int days) {
132 searchLogBhv.queryDelete(cb -> {
133 cb.query().setRequestedAt_LessEqual(systemHelper.getCurrentTimeAsLocalDateTime().minusDays(days));
134 });
135 }
136
137
138
139
140
141
142 public void deleteClickLogBefore(final int days) {
143 clickLogBhv.queryDelete(cb -> {
144 cb.query().setRequestedAt_LessEqual(systemHelper.getCurrentTimeAsLocalDateTime().minusDays(days));
145 });
146 }
147
148
149
150
151
152
153 public void deleteFavoriteLogBefore(final int days) {
154 favoriteLogBhv.queryDelete(cb -> {
155 cb.query().setCreatedAt_LessEqual(systemHelper.getCurrentTimeAsLocalDateTime().minusDays(days));
156 });
157 }
158
159
160
161
162
163
164
165
166
167
168 public List<?> getSearchLogList(final SearchLogPager pager) {
169 final EsPagingResultBean<?> list;
170 if (SearchLogPager.LOG_TYPE_USERINFO.equalsIgnoreCase(pager.logType)) {
171 list = (EsPagingResultBean<?>) userInfoBhv.selectPage(cb -> {
172 cb.paging(pager.getPageSize(), pager.getCurrentPageNumber());
173 cb.query().addOrderBy_UpdatedAt_Desc();
174 createUserInfoCondition(pager, cb);
175 });
176 } else if (SearchLogPager.LOG_TYPE_CLICK.equalsIgnoreCase(pager.logType)) {
177 list = (EsPagingResultBean<?>) clickLogBhv.selectPage(cb -> {
178 cb.paging(pager.getPageSize(), pager.getCurrentPageNumber());
179 cb.query().addOrderBy_RequestedAt_Desc();
180 createClickLogCondition(pager, cb);
181 });
182 } else if (SearchLogPager.LOG_TYPE_CLICK_COUNT.equalsIgnoreCase(pager.logType)) {
183 list = (EsPagingResultBean<?>) clickLogBhv.selectPage(cb -> {
184 cb.fetchFirst(0);
185 createClickLogCondition(pager, cb);
186 cb.aggregation().setUrl_Terms(SearchLogPager.LOG_TYPE_CLICK_COUNT, op -> {
187 op.size(pager.getPageSize());
188 if (fessConfig.getSearchlogAggShardSizeAsInteger() >= 0) {
189 op.shardSize(fessConfig.getSearchlogAggShardSizeAsInteger());
190 }
191 }, null);
192 });
193 final Terms agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_CLICK_COUNT);
194 final List<? extends Terms.Bucket> buckets = agg.getBuckets();
195 updatePagerByAgg(pager, buckets.size());
196 return buckets.stream().map(e -> {
197 final Map<String, Object> map = new HashMap<>();
198 map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8)));
199 map.put(KEY, e.getKeyAsString());
200 map.put(COUNT, e.getDocCount());
201 return map;
202 }).collect(Collectors.toList());
203 } else if (SearchLogPager.LOG_TYPE_FAVORITE.equalsIgnoreCase(pager.logType)) {
204 list = (EsPagingResultBean<?>) favoriteLogBhv.selectPage(cb -> {
205 cb.paging(pager.getPageSize(), pager.getCurrentPageNumber());
206 cb.query().addOrderBy_CreatedAt_Desc();
207 createFavoriteLogCondition(pager, cb);
208 });
209 } else if (SearchLogPager.LOG_TYPE_FAVORITE_COUNT.equalsIgnoreCase(pager.logType)) {
210 list = (EsPagingResultBean<?>) favoriteLogBhv.selectPage(cb -> {
211 cb.fetchFirst(0);
212 createFavoriteLogCondition(pager, cb);
213 cb.aggregation().setUrl_Terms(SearchLogPager.LOG_TYPE_FAVORITE_COUNT, op -> {
214 op.size(pager.getPageSize());
215 if (fessConfig.getSearchlogAggShardSizeAsInteger() >= 0) {
216 op.shardSize(fessConfig.getSearchlogAggShardSizeAsInteger());
217 }
218 }, null);
219 });
220 final Terms agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_FAVORITE_COUNT);
221 final List<? extends Terms.Bucket> buckets = agg.getBuckets();
222 updatePagerByAgg(pager, buckets.size());
223 return buckets.stream().map(e -> {
224 final Map<String, Object> map = new HashMap<>();
225 map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8)));
226 map.put(KEY, e.getKeyAsString());
227 map.put(COUNT, e.getDocCount());
228 return map;
229 }).collect(Collectors.toList());
230 } else if (SearchLogPager.LOG_TYPE_SEARCH_COUNT_HOUR.equalsIgnoreCase(pager.logType)) {
231 list = (EsPagingResultBean<?>) searchLogBhv.selectPage(cb -> {
232 cb.fetchFirst(0);
233 createSearchLogCondition(pager, cb);
234 cb.aggregation().setRequestedAt_DateHistogram(SearchLogPager.LOG_TYPE_SEARCH_COUNT_HOUR, op -> {
235 op.calendarInterval(DateHistogramInterval.HOUR);
236 op.minDocCount(0);
237 op.order(BucketOrder.key(true));
238 }, null);
239 });
240 final Histogram agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_SEARCH_COUNT_HOUR);
241 final List<? extends Histogram.Bucket> buckets = agg.getBuckets();
242 updatePagerByAgg(pager, buckets.size());
243 return buckets.stream().map(e -> {
244 final Map<String, Object> map = new HashMap<>();
245 map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8)));
246 map.put(KEY, e.getKeyAsString());
247 map.put(COUNT, e.getDocCount());
248 return map;
249 }).collect(Collectors.toList());
250 } else if (SearchLogPager.LOG_TYPE_SEARCH_COUNT_DAY.equalsIgnoreCase(pager.logType)) {
251 list = (EsPagingResultBean<?>) searchLogBhv.selectPage(cb -> {
252 cb.fetchFirst(0);
253 createSearchLogCondition(pager, cb);
254 cb.aggregation().setRequestedAt_DateHistogram(SearchLogPager.LOG_TYPE_SEARCH_COUNT_DAY, op -> {
255 op.calendarInterval(DateHistogramInterval.DAY);
256 op.minDocCount(0);
257 op.order(BucketOrder.key(true));
258 }, null);
259 });
260 final Histogram agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_SEARCH_COUNT_DAY);
261 final List<? extends Histogram.Bucket> buckets = agg.getBuckets();
262 updatePagerByAgg(pager, buckets.size());
263 return buckets.stream().map(e -> {
264 final Map<String, Object> map = new HashMap<>();
265 map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8)));
266 map.put(KEY, e.getKeyAsString());
267 map.put(COUNT, e.getDocCount());
268 return map;
269 }).collect(Collectors.toList());
270 } else if (SearchLogPager.LOG_TYPE_SEARCH_USER_HOUR.equalsIgnoreCase(pager.logType)) {
271 list = (EsPagingResultBean<?>) searchLogBhv.selectPage(cb -> {
272 cb.fetchFirst(0);
273 createSearchLogCondition(pager, cb);
274 cb.aggregation().setRequestedAt_DateHistogram(SearchLogPager.LOG_TYPE_SEARCH_USER_HOUR, op -> {
275 op.calendarInterval(DateHistogramInterval.HOUR);
276 op.subAggregation(AggregationBuilders.cardinality(USER_INFO_ID).field(USER_INFO_ID));
277 op.minDocCount(0);
278 op.order(BucketOrder.key(true));
279 }, null);
280 });
281 final Histogram agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_SEARCH_USER_HOUR);
282 final List<? extends Histogram.Bucket> buckets = agg.getBuckets();
283 updatePagerByAgg(pager, buckets.size());
284 return buckets.stream().map(e -> {
285 final Map<String, Object> map = new HashMap<>();
286 map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8)));
287 map.put(KEY, e.getKeyAsString());
288 final Cardinality value = e.getAggregations().get(USER_INFO_ID);
289 map.put(COUNT, value.getValue());
290 return map;
291 }).collect(Collectors.toList());
292 } else if (SearchLogPager.LOG_TYPE_SEARCH_USER_DAY.equalsIgnoreCase(pager.logType)) {
293 list = (EsPagingResultBean<?>) searchLogBhv.selectPage(cb -> {
294 cb.fetchFirst(0);
295 createSearchLogCondition(pager, cb);
296 cb.aggregation().setRequestedAt_DateHistogram(SearchLogPager.LOG_TYPE_SEARCH_USER_DAY, op -> {
297 op.calendarInterval(DateHistogramInterval.DAY);
298 op.subAggregation(AggregationBuilders.cardinality(USER_INFO_ID).field(USER_INFO_ID));
299 op.minDocCount(0);
300 op.order(BucketOrder.key(true));
301 }, null);
302 });
303 final Histogram agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_SEARCH_USER_DAY);
304 final List<? extends Histogram.Bucket> buckets = agg.getBuckets();
305 updatePagerByAgg(pager, buckets.size());
306 return buckets.stream().map(e -> {
307 final Map<String, Object> map = new HashMap<>();
308 map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8)));
309 map.put(KEY, e.getKeyAsString());
310 final Cardinality value = e.getAggregations().get(USER_INFO_ID);
311 map.put(COUNT, value.getValue());
312 return map;
313 }).collect(Collectors.toList());
314 } else if (SearchLogPager.LOG_TYPE_SEARCH_REQTIMEAVG_HOUR.equalsIgnoreCase(pager.logType)) {
315 list = (EsPagingResultBean<?>) searchLogBhv.selectPage(cb -> {
316 cb.fetchFirst(0);
317 createSearchLogCondition(pager, cb);
318 cb.aggregation().setRequestedAt_DateHistogram(SearchLogPager.LOG_TYPE_SEARCH_REQTIMEAVG_HOUR, op -> {
319 op.calendarInterval(DateHistogramInterval.HOUR);
320 op.subAggregation(AggregationBuilders.avg(QUERY_TIME).field(QUERY_TIME));
321 op.minDocCount(0);
322 op.order(BucketOrder.key(true));
323 }, null);
324 });
325 final Histogram agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_SEARCH_REQTIMEAVG_HOUR);
326 final List<? extends Histogram.Bucket> buckets = agg.getBuckets();
327 updatePagerByAgg(pager, buckets.size());
328 return buckets.stream().map(e -> {
329 final Map<String, Object> map = new HashMap<>();
330 map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8)));
331 map.put(KEY, e.getKeyAsString());
332 final Avg value = e.getAggregations().get(QUERY_TIME);
333 map.put(COUNT, value.getValueAsString());
334 return map;
335 }).collect(Collectors.toList());
336 } else if (SearchLogPager.LOG_TYPE_SEARCH_REQTIMEAVG_DAY.equalsIgnoreCase(pager.logType)) {
337 list = (EsPagingResultBean<?>) searchLogBhv.selectPage(cb -> {
338 cb.fetchFirst(0);
339 createSearchLogCondition(pager, cb);
340 cb.aggregation().setRequestedAt_DateHistogram(SearchLogPager.LOG_TYPE_SEARCH_REQTIMEAVG_DAY, op -> {
341 op.calendarInterval(DateHistogramInterval.DAY);
342 op.subAggregation(AggregationBuilders.avg(QUERY_TIME).field(QUERY_TIME));
343 op.minDocCount(0);
344 op.order(BucketOrder.key(true));
345 }, null);
346 });
347 final Histogram agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_SEARCH_REQTIMEAVG_DAY);
348 final List<? extends Histogram.Bucket> buckets = agg.getBuckets();
349 updatePagerByAgg(pager, buckets.size());
350 return buckets.stream().map(e -> {
351 final Map<String, Object> map = new HashMap<>();
352 map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8)));
353 map.put(KEY, e.getKeyAsString());
354 final Avg value = e.getAggregations().get(QUERY_TIME);
355 map.put(COUNT, value.getValueAsString());
356 return map;
357 }).collect(Collectors.toList());
358 } else if (SearchLogPager.LOG_TYPE_SEARCH_KEYWORD.equalsIgnoreCase(pager.logType)) {
359 list = (EsPagingResultBean<?>) searchLogBhv.selectPage(cb -> {
360 cb.fetchFirst(0);
361 createSearchLogCondition(pager, cb);
362 cb.aggregation().setSearchWord_Terms(SearchLogPager.LOG_TYPE_SEARCH_KEYWORD, op -> {
363 op.size(pager.getPageSize());
364 if (fessConfig.getSearchlogAggShardSizeAsInteger() >= 0) {
365 op.shardSize(fessConfig.getSearchlogAggShardSizeAsInteger());
366 }
367 }, null);
368 });
369 final Terms agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_SEARCH_KEYWORD);
370 final List<? extends Terms.Bucket> buckets = agg.getBuckets();
371 updatePagerByAgg(pager, buckets.size());
372 return buckets.stream().map(e -> {
373 final Map<String, Object> map = new HashMap<>();
374 map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8)));
375 map.put(KEY, e.getKeyAsString());
376 map.put(COUNT, e.getDocCount());
377 return map;
378 }).collect(Collectors.toList());
379 } else if (SearchLogPager.LOG_TYPE_SEARCH_ZEROHIT.equalsIgnoreCase(pager.logType)) {
380 list = (EsPagingResultBean<?>) searchLogBhv.selectPage(cb -> {
381 cb.fetchFirst(0);
382 createSearchLogCondition(pager, cb);
383 cb.query().setHitCount_Equal(0L);
384 cb.aggregation().setSearchWord_Terms(SearchLogPager.LOG_TYPE_SEARCH_ZEROHIT, op -> {
385 op.size(pager.getPageSize());
386 if (fessConfig.getSearchlogAggShardSizeAsInteger() >= 0) {
387 op.shardSize(fessConfig.getSearchlogAggShardSizeAsInteger());
388 }
389 }, null);
390 });
391 final Terms agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_SEARCH_ZEROHIT);
392 final List<? extends Terms.Bucket> buckets = agg.getBuckets();
393 updatePagerByAgg(pager, buckets.size());
394 return buckets.stream().map(e -> {
395 final Map<String, Object> map = new HashMap<>();
396 map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8)));
397 map.put(KEY, e.getKeyAsString());
398 map.put(COUNT, e.getDocCount());
399 return map;
400 }).collect(Collectors.toList());
401
402
403
404
405
406
407 } else {
408 list = (EsPagingResultBean<?>) searchLogBhv.selectPage(cb -> {
409 cb.paging(pager.getPageSize(), pager.getCurrentPageNumber());
410 cb.query().addOrderBy_RequestedAt_Desc();
411 createSearchLogCondition(pager, cb);
412 });
413 }
414
415
416 BeanUtil.copyBeanToBean(list, pager, option -> option.include(Constants.PAGER_CONVERSION_RULE));
417 pager.setPageNumberList(list.pageRange(op -> {
418 op.rangeSize(fessConfig.getPagingPageRangeSizeAsInteger());
419 }).createPageNumberList());
420
421 return list;
422 }
423
424
425
426
427
428
429
430 private void updatePagerByAgg(final SearchLogPager pager, final int size) {
431 pager.setAllPageCount(1);
432 pager.setAllRecordCount(size);
433 pager.setCurrentPageNumber(1);
434 pager.setExistNextPage(false);
435 pager.setExistPrePage(false);
436 pager.setPageSize(pager.getPageSize());
437 }
438
439
440
441
442
443
444
445 private void createSearchLogCondition(final SearchLogPager pager, final SearchLogCB cb) {
446 if (StringUtil.isNotBlank(pager.queryId)) {
447 cb.query().setQueryId_Term(pager.queryId);
448 }
449 if (StringUtil.isNotBlank(pager.userSessionId)) {
450 cb.query().setUserSessionId_Term(pager.userSessionId);
451 }
452 if (StringUtil.isNotBlank(pager.accessType)) {
453 cb.query().setAccessType_Term(pager.accessType);
454 }
455 if (StringUtil.isNotBlank(pager.requestedTimeRange)) {
456 final String[] values = pager.requestedTimeRange.split(" - ");
457 final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM);
458 try {
459 if (values.length > 0) {
460 cb.query().setRequestedAt_GreaterEqual(parseDateTime(values[0], formatter));
461 }
462 if (values.length > 1) {
463 cb.query().setRequestedAt_LessEqual(LocalDateTime.parse(values[1], formatter));
464 }
465 } catch (final Exception e) {
466 if (logger.isDebugEnabled()) {
467 logger.debug("Failed to parse {}", pager.requestedTimeRange, e);
468 }
469 }
470 }
471 }
472
473
474
475
476
477
478
479 private void createFavoriteLogCondition(final SearchLogPager pager, final FavoriteLogCB cb) {
480 if (StringUtil.isNotBlank(pager.queryId)) {
481 cb.query().setQueryId_Term(pager.queryId);
482 }
483 if (StringUtil.isNotBlank(pager.userSessionId)) {
484 cb.query().setUserInfoId_Term(pager.userSessionId);
485 }
486 if (StringUtil.isNotBlank(pager.requestedTimeRange)) {
487 final String[] values = pager.requestedTimeRange.split(" - ");
488 final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM);
489 try {
490 if (values.length > 0) {
491 cb.query().setCreatedAt_GreaterEqual(LocalDateTime.parse(values[0], formatter));
492 }
493 if (values.length > 1) {
494 cb.query().setCreatedAt_LessEqual(parseDateTime(values[1], formatter));
495 }
496 } catch (final Exception e) {
497 if (logger.isDebugEnabled()) {
498 logger.debug("Failed to parse {}", pager.requestedTimeRange, e);
499 }
500 }
501 }
502 }
503
504
505
506
507
508
509
510 private void createUserInfoCondition(final SearchLogPager pager, final UserInfoCB cb) {
511 if (StringUtil.isNotBlank(pager.userSessionId)) {
512 cb.query().setId_Equal(pager.userSessionId);
513 }
514 if (StringUtil.isNotBlank(pager.requestedTimeRange)) {
515 final String[] values = pager.requestedTimeRange.split(" - ");
516 final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM);
517 try {
518 if (values.length > 0) {
519 cb.query().setUpdatedAt_GreaterEqual(LocalDateTime.parse(values[0], formatter));
520 }
521 if (values.length > 1) {
522 cb.query().setUpdatedAt_LessEqual(LocalDateTime.parse(values[1], formatter));
523 }
524 } catch (final Exception e) {
525 if (logger.isDebugEnabled()) {
526 logger.debug("Failed to parse {}", pager.requestedTimeRange, e);
527 }
528 }
529 }
530 }
531
532
533
534
535
536
537
538 private void createClickLogCondition(final SearchLogPager pager, final ClickLogCB cb) {
539 if (StringUtil.isNotBlank(pager.queryId)) {
540 cb.query().setQueryId_Term(pager.queryId);
541 }
542 if (StringUtil.isNotBlank(pager.userSessionId)) {
543 cb.query().setUserSessionId_Term(pager.userSessionId);
544 }
545 if (StringUtil.isNotBlank(pager.requestedTimeRange)) {
546 final String[] values = pager.requestedTimeRange.split(" - ");
547 final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM);
548 try {
549 if (values.length > 0) {
550 cb.query().setRequestedAt_GreaterEqual(LocalDateTime.parse(values[0], formatter));
551 }
552 if (values.length > 1) {
553 cb.query().setRequestedAt_LessEqual(LocalDateTime.parse(values[1], formatter));
554 }
555 } catch (final Exception e) {
556 if (logger.isDebugEnabled()) {
557 logger.debug("Failed to parse {}", pager.requestedTimeRange, e);
558 }
559 }
560 }
561 }
562
563
564
565
566
567
568
569
570 protected LocalDateTime parseDateTime(final String value, final DateTimeFormatter formatter) {
571 return LocalDateTime.parse(value, formatter).atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime();
572 }
573
574
575
576
577
578
579
580
581 public OptionalEntity<?> getSearchLog(final String logType, final String id) {
582 if (SearchLogPager.LOG_TYPE_CLICK.equalsIgnoreCase(logType)) {
583 return clickLogBhv.selectByPK(id);
584 }
585 if (SearchLogPager.LOG_TYPE_FAVORITE.equalsIgnoreCase(logType)) {
586 return favoriteLogBhv.selectByPK(id);
587 }
588 if (SearchLogPager.LOG_TYPE_USERINFO.equalsIgnoreCase(logType)) {
589 return userInfoBhv.selectByPK(id);
590 }
591 return searchLogBhv.selectByPK(id);
592 }
593
594
595
596
597
598
599
600
601 public Map<String, String> getSearchLogMap(final String logType, final String id) {
602 if (SearchLogPager.LOG_TYPE_USERINFO.equalsIgnoreCase(logType)) {
603 return userInfoBhv.selectByPK(id).map(e -> {
604 final Map<String, String> params = new LinkedHashMap<>();
605 params.put("User Info ID", e.getId());
606 params.put("Created Time", FessFunctions.formatDate(e.getCreatedAt()));
607 params.put("Updated Time", FessFunctions.formatDate(e.getUpdatedAt()));
608 return params;
609 }).get();
610 }
611 if (SearchLogPager.LOG_TYPE_CLICK.equalsIgnoreCase(logType)) {
612 return clickLogBhv.selectByPK(id).map(e -> {
613 final Map<String, String> params = new LinkedHashMap<>();
614 params.put("ID", e.getId());
615 params.put("Query ID", e.getQueryId());
616 params.put("Doc ID", e.getDocId());
617 params.put("User Session ID", e.getUserSessionId());
618 params.put("URL", e.getUrl());
619 params.put("URL ID", e.getUrlId());
620 params.put("Order", toNumberString(e.getOrder()));
621 params.put("Query Requested Time", FessFunctions.formatDate(e.getQueryRequestedAt()));
622 params.put("Requested Time", FessFunctions.formatDate(e.getRequestedAt()));
623 return params;
624 }).get();
625 }
626 if (SearchLogPager.LOG_TYPE_FAVORITE.equalsIgnoreCase(logType)) {
627 return favoriteLogBhv.selectByPK(id).map(e -> {
628 final Map<String, String> params = new LinkedHashMap<>();
629 params.put("ID", e.getId());
630 params.put("Query ID", e.getQueryId());
631 params.put("Doc ID", e.getDocId());
632 params.put("User Info ID", e.getUserInfoId());
633 params.put("URL", e.getUrl());
634 params.put("Created Time", FessFunctions.formatDate(e.getCreatedAt()));
635 params.put("Requested Time", FessFunctions.formatDate(e.getRequestedAt()));
636 return params;
637 }).get();
638 }
639 return searchLogBhv.selectByPK(id).map(e -> {
640 final Map<String, String> params = new LinkedHashMap<>();
641 params.put("ID", e.getId());
642 params.put("Query ID", e.getQueryId());
643 params.put("User Info ID", e.getUserInfoId());
644 params.put("User Session ID", e.getUserSessionId());
645 params.put("Access Type", e.getAccessType());
646 params.put("Search Word", e.getSearchWord());
647 params.put("Requested Time", FessFunctions.formatDate(e.getRequestedAt()));
648 params.put("Query Time", toNumberString(e.getQueryTime()));
649 params.put("Response Time", toNumberString(e.getResponseTime()));
650 params.put("Hit Count", toNumberString(e.getHitCount()));
651 params.put("Offset", toNumberString(e.getQueryOffset()));
652 params.put("Page Size", toNumberString(e.getQueryPageSize()));
653 params.put("Client IP", e.getClientIp());
654 params.put("Referer", e.getReferer());
655 params.put("Languages", e.getLanguages());
656 params.put("Virtual Host", e.getVirtualHost());
657 params.put("Roles", e.getRoles() != null ? String.join(" ", e.getRoles()) : StringUtil.EMPTY);
658 params.put("User Agent", e.getUserAgent());
659 e.getSearchFieldLogList().stream().forEach(p -> {
660 params.put(p.getFirst(), p.getSecond());
661 });
662 e.getRequestHeaderList().stream().forEach(p -> {
663 params.put(p.getFirst(), p.getSecond());
664 });
665 return params;
666 }).get();
667 }
668
669
670
671
672
673
674
675 private String toNumberString(final Number value) {
676 return value != null ? value.toString() : StringUtil.EMPTY;
677 }
678
679
680
681
682
683
684
685 public void deleteSearchLog(final Object e) {
686 if (e instanceof final ClickLog clickLog) {
687 clickLogBhv.delete(clickLog);
688 } else if (e instanceof final FavoriteLog favoriteLog) {
689 favoriteLogBhv.delete(favoriteLog);
690 } else if (e instanceof final UserInfo userInfo) {
691 userInfoBhv.delete(userInfo);
692 } else if (e instanceof final SearchLog searchLog) {
693 searchLogBhv.delete(searchLog);
694 } else {
695 throw new FessSystemException("Unknown log entity: " + e);
696 }
697 }
698 }