diff --git a/src/main/java/org/codelibs/fess/app/pager/SearchLogPager.java b/src/main/java/org/codelibs/fess/app/pager/SearchLogPager.java index e698b395c..d98adbfcf 100644 --- a/src/main/java/org/codelibs/fess/app/pager/SearchLogPager.java +++ b/src/main/java/org/codelibs/fess/app/pager/SearchLogPager.java @@ -26,8 +26,28 @@ public class SearchLogPager implements Serializable { public static final String LOG_TYPE_SEARCH = "search"; + public static final String LOG_TYPE_SEARCH_COUNT_HOUR = "search_count_hour_agg"; + + public static final String LOG_TYPE_SEARCH_COUNT_DAY = "search_count_day_agg"; + + public static final String LOG_TYPE_SEARCH_USER_HOUR = "search_user_hour_agg"; + + public static final String LOG_TYPE_SEARCH_USER_DAY = "search_user_day_agg"; + + public static final String LOG_TYPE_SEARCH_REQTIMEAVG_HOUR = "search_reqtimeavg_hour_agg"; + + public static final String LOG_TYPE_SEARCH_REQTIMEAVG_DAY = "search_reqtimeavg_day_agg"; + + public static final String LOG_TYPE_SEARCH_KEYWORD = "search_keyword_agg"; + + public static final String LOG_TYPE_SEARCH_ZEROHIT = "search_zerohit_agg"; + + public static final String LOG_TYPE_SEARCH_ZEROCLICK = "search_zeroclick_agg"; + public static final String LOG_TYPE_CLICK = "click"; + public static final String LOG_TYPE_CLICK_TOP = "click_top_agg"; + public static final String LOG_TYPE_FAVORITE = "favorite"; public static final int DEFAULT_PAGE_SIZE = 20; diff --git a/src/main/java/org/codelibs/fess/app/service/SearchLogService.java b/src/main/java/org/codelibs/fess/app/service/SearchLogService.java index 7d91e4832..d8248fd92 100644 --- a/src/main/java/org/codelibs/fess/app/service/SearchLogService.java +++ b/src/main/java/org/codelibs/fess/app/service/SearchLogService.java @@ -15,12 +15,17 @@ */ package org.codelibs.fess.app.service; +import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; +import java.util.Base64; +import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import javax.annotation.Resource; @@ -28,6 +33,10 @@ import org.codelibs.core.beans.util.BeanUtil; import org.codelibs.core.lang.StringUtil; import org.codelibs.fess.Constants; import org.codelibs.fess.app.pager.SearchLogPager; +import org.codelibs.fess.es.log.allcommon.EsPagingResultBean; +import org.codelibs.fess.es.log.cbean.ClickLogCB; +import org.codelibs.fess.es.log.cbean.FavoriteLogCB; +import org.codelibs.fess.es.log.cbean.SearchLogCB; import org.codelibs.fess.es.log.exbhv.ClickLogBhv; import org.codelibs.fess.es.log.exbhv.FavoriteLogBhv; import org.codelibs.fess.es.log.exbhv.SearchLogBhv; @@ -38,12 +47,29 @@ import org.codelibs.fess.exception.FessSystemException; import org.codelibs.fess.helper.SystemHelper; import org.codelibs.fess.mylasta.direction.FessConfig; import org.codelibs.fess.taglib.FessFunctions; -import org.dbflute.cbean.result.PagingResultBean; import org.dbflute.optional.OptionalEntity; +import org.elasticsearch.search.aggregations.AggregationBuilders; +import org.elasticsearch.search.aggregations.BucketOrder; +import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval; +import org.elasticsearch.search.aggregations.bucket.histogram.Histogram; +import org.elasticsearch.search.aggregations.bucket.terms.Terms; +import org.elasticsearch.search.aggregations.metrics.avg.Avg; +import org.elasticsearch.search.aggregations.metrics.cardinality.Cardinality; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SearchLogService { + + private static final String COUNT = "count"; + + private static final String KEY = "key"; + + private static final String ID = "id"; + + private static final String USER_INFO_ID = "userInfoId"; + + private static final String QUERY_TIME = "queryTime"; + private static final Logger logger = LoggerFactory.getLogger(SearchLogService.class); @Resource @@ -67,91 +93,205 @@ public class SearchLogService { }); } - public PagingResultBean getSearchLogList(final SearchLogPager pager) { - final PagingResultBean list; - if (SearchLogPager.LOG_TYPE_CLICK.equalsIgnoreCase(pager.logType)) { - list = clickLogBhv.selectPage(cb -> { + public List getSearchLogList(final SearchLogPager pager) { + final EsPagingResultBean list; + if (SearchLogPager.LOG_TYPE_CLICK.equalsIgnoreCase(pager.logType) + || SearchLogPager.LOG_TYPE_CLICK_TOP.equalsIgnoreCase(pager.logType)) { + list = (EsPagingResultBean) clickLogBhv.selectPage(cb -> { cb.paging(pager.getPageSize(), pager.getCurrentPageNumber()); cb.query().addOrderBy_RequestedAt_Desc(); - if (StringUtil.isNotBlank(pager.queryId)) { - cb.query().setQueryId_Term(pager.queryId); - } - if (StringUtil.isNotBlank(pager.userSessionId)) { - cb.query().setUserSessionId_Term(pager.userSessionId); - } - if (StringUtil.isNotBlank(pager.requestedTimeRange)) { - String[] values = pager.requestedTimeRange.split(" - "); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); - try { - if (values.length > 0) { - cb.query().setRequestedAt_GreaterEqual(LocalDateTime.parse(values[0], formatter)); - } - if (values.length > 1) { - cb.query().setRequestedAt_LessEqual(LocalDateTime.parse(values[1], formatter)); - } - } catch (Exception e) { - if (logger.isDebugEnabled()) { - logger.debug("Failed to parse " + pager.requestedTimeRange, e); - } - } - } + createClickLogCondition(pager, cb); + }); + } else if (SearchLogPager.LOG_TYPE_CLICK_TOP.equalsIgnoreCase(pager.logType)) { + list = (EsPagingResultBean) clickLogBhv.selectPage(cb -> { + cb.fetchFirst(0); + createClickLogCondition(pager, cb); + cb.aggregation().filter("top_click_filter", null, null, aggs -> { + aggs.setUrl_Count(); + }); }); } else if (SearchLogPager.LOG_TYPE_FAVORITE.equalsIgnoreCase(pager.logType)) { - list = favoriteLogBhv.selectPage(cb -> { + list = (EsPagingResultBean) favoriteLogBhv.selectPage(cb -> { cb.paging(pager.getPageSize(), pager.getCurrentPageNumber()); cb.query().addOrderBy_CreatedAt_Desc(); - if (StringUtil.isNotBlank(pager.queryId)) { - cb.query().setQueryId_Term(pager.queryId); - } - if (StringUtil.isNotBlank(pager.userSessionId)) { - cb.query().setUserInfoId_Term(pager.userSessionId); - } - if (StringUtil.isNotBlank(pager.requestedTimeRange)) { - String[] values = pager.requestedTimeRange.split(" - "); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); - try { - if (values.length > 0) { - cb.query().setCreatedAt_GreaterEqual(LocalDateTime.parse(values[0], formatter)); - } - if (values.length > 1) { - cb.query().setCreatedAt_LessEqual(parseDateTime(values[1], formatter)); - } - } catch (Exception e) { - if (logger.isDebugEnabled()) { - logger.debug("Failed to parse " + pager.requestedTimeRange, e); - } - } - } + createFavoriteLogCondition(pager, cb); }); + } else if (SearchLogPager.LOG_TYPE_SEARCH_COUNT_HOUR.equalsIgnoreCase(pager.logType)) { + list = (EsPagingResultBean) searchLogBhv.selectPage(cb -> { + cb.fetchFirst(0); + createSearchLogCondition(pager, cb); + cb.aggregation().setRequestedAt_DateHistogram(SearchLogPager.LOG_TYPE_SEARCH_COUNT_HOUR, op -> { + op.dateHistogramInterval(DateHistogramInterval.HOUR); + op.minDocCount(0); + op.order(BucketOrder.key(true)); + }, null); + }); + final Histogram agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_SEARCH_COUNT_HOUR); + final List buckets = agg.getBuckets(); + updatePagerByAgg(pager, buckets.size()); + return buckets.stream().map(e -> { + final Map map = new HashMap<>(); + map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8))); + map.put(KEY, e.getKeyAsString()); + map.put(COUNT, e.getDocCount()); + return map; + }).collect(Collectors.toList()); + } else if (SearchLogPager.LOG_TYPE_SEARCH_COUNT_DAY.equalsIgnoreCase(pager.logType)) { + list = (EsPagingResultBean) searchLogBhv.selectPage(cb -> { + cb.fetchFirst(0); + createSearchLogCondition(pager, cb); + cb.aggregation().setRequestedAt_DateHistogram(SearchLogPager.LOG_TYPE_SEARCH_COUNT_DAY, op -> { + op.dateHistogramInterval(DateHistogramInterval.DAY); + op.minDocCount(0); + op.order(BucketOrder.key(true)); + }, null); + }); + final Histogram agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_SEARCH_COUNT_DAY); + final List buckets = agg.getBuckets(); + updatePagerByAgg(pager, buckets.size()); + return buckets.stream().map(e -> { + final Map map = new HashMap<>(); + map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8))); + map.put(KEY, e.getKeyAsString()); + map.put(COUNT, e.getDocCount()); + return map; + }).collect(Collectors.toList()); + } else if (SearchLogPager.LOG_TYPE_SEARCH_USER_HOUR.equalsIgnoreCase(pager.logType)) { + list = (EsPagingResultBean) searchLogBhv.selectPage(cb -> { + cb.fetchFirst(0); + createSearchLogCondition(pager, cb); + cb.aggregation().setRequestedAt_DateHistogram(SearchLogPager.LOG_TYPE_SEARCH_USER_HOUR, op -> { + op.dateHistogramInterval(DateHistogramInterval.HOUR); + op.subAggregation(AggregationBuilders.cardinality(USER_INFO_ID).field(USER_INFO_ID)); + op.minDocCount(0); + op.order(BucketOrder.key(true)); + }, null); + }); + final Histogram agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_SEARCH_USER_HOUR); + final List buckets = agg.getBuckets(); + updatePagerByAgg(pager, buckets.size()); + return buckets.stream().map(e -> { + final Map map = new HashMap<>(); + map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8))); + map.put(KEY, e.getKeyAsString()); + final Cardinality value = e.getAggregations().get(USER_INFO_ID); + map.put(COUNT, value.getValue()); + return map; + }).collect(Collectors.toList()); + } else if (SearchLogPager.LOG_TYPE_SEARCH_USER_DAY.equalsIgnoreCase(pager.logType)) { + list = (EsPagingResultBean) searchLogBhv.selectPage(cb -> { + cb.fetchFirst(0); + createSearchLogCondition(pager, cb); + cb.aggregation().setRequestedAt_DateHistogram(SearchLogPager.LOG_TYPE_SEARCH_USER_DAY, op -> { + op.dateHistogramInterval(DateHistogramInterval.DAY); + op.subAggregation(AggregationBuilders.cardinality(USER_INFO_ID).field(USER_INFO_ID)); + op.minDocCount(0); + op.order(BucketOrder.key(true)); + }, null); + }); + final Histogram agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_SEARCH_USER_DAY); + final List buckets = agg.getBuckets(); + updatePagerByAgg(pager, buckets.size()); + return buckets.stream().map(e -> { + final Map map = new HashMap<>(); + map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8))); + map.put(KEY, e.getKeyAsString()); + final Cardinality value = e.getAggregations().get(USER_INFO_ID); + map.put(COUNT, value.getValue()); + return map; + }).collect(Collectors.toList()); + } else if (SearchLogPager.LOG_TYPE_SEARCH_REQTIMEAVG_HOUR.equalsIgnoreCase(pager.logType)) { + list = (EsPagingResultBean) searchLogBhv.selectPage(cb -> { + cb.fetchFirst(0); + createSearchLogCondition(pager, cb); + cb.aggregation().setRequestedAt_DateHistogram(SearchLogPager.LOG_TYPE_SEARCH_REQTIMEAVG_HOUR, op -> { + op.dateHistogramInterval(DateHistogramInterval.HOUR); + op.subAggregation(AggregationBuilders.avg(QUERY_TIME).field(QUERY_TIME)); + op.minDocCount(0); + op.order(BucketOrder.key(true)); + }, null); + }); + final Histogram agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_SEARCH_REQTIMEAVG_HOUR); + final List buckets = agg.getBuckets(); + updatePagerByAgg(pager, buckets.size()); + return buckets.stream().map(e -> { + final Map map = new HashMap<>(); + map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8))); + map.put(KEY, e.getKeyAsString()); + final Avg value = e.getAggregations().get(QUERY_TIME); + map.put(COUNT, value.getValueAsString()); + return map; + }).collect(Collectors.toList()); + } else if (SearchLogPager.LOG_TYPE_SEARCH_REQTIMEAVG_DAY.equalsIgnoreCase(pager.logType)) { + list = (EsPagingResultBean) searchLogBhv.selectPage(cb -> { + cb.fetchFirst(0); + createSearchLogCondition(pager, cb); + cb.aggregation().setRequestedAt_DateHistogram(SearchLogPager.LOG_TYPE_SEARCH_REQTIMEAVG_DAY, op -> { + op.dateHistogramInterval(DateHistogramInterval.DAY); + op.subAggregation(AggregationBuilders.avg(QUERY_TIME).field(QUERY_TIME)); + op.minDocCount(0); + op.order(BucketOrder.key(true)); + }, null); + }); + final Histogram agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_SEARCH_REQTIMEAVG_DAY); + final List buckets = agg.getBuckets(); + updatePagerByAgg(pager, buckets.size()); + return buckets.stream().map(e -> { + final Map map = new HashMap<>(); + map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8))); + map.put(KEY, e.getKeyAsString()); + final Avg value = e.getAggregations().get(QUERY_TIME); + map.put(COUNT, value.getValueAsString()); + return map; + }).collect(Collectors.toList()); + } else if (SearchLogPager.LOG_TYPE_SEARCH_KEYWORD.equalsIgnoreCase(pager.logType)) { + list = (EsPagingResultBean) searchLogBhv.selectPage(cb -> { + cb.fetchFirst(0); + createSearchLogCondition(pager, cb); + cb.aggregation().setSearchWord_Terms(SearchLogPager.LOG_TYPE_SEARCH_KEYWORD, op -> { + op.size(pager.getPageSize()); + }, null); + }); + final Terms agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_SEARCH_KEYWORD); + final List buckets = agg.getBuckets(); + updatePagerByAgg(pager, buckets.size()); + return buckets.stream().map(e -> { + final Map map = new HashMap<>(); + map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8))); + map.put(KEY, e.getKeyAsString()); + map.put(COUNT, e.getDocCount()); + return map; + }).collect(Collectors.toList()); + } else if (SearchLogPager.LOG_TYPE_SEARCH_ZEROHIT.equalsIgnoreCase(pager.logType)) { + list = (EsPagingResultBean) searchLogBhv.selectPage(cb -> { + cb.fetchFirst(0); + createSearchLogCondition(pager, cb); + cb.query().setHitCount_Equal(0L); + cb.aggregation().setSearchWord_Terms(SearchLogPager.LOG_TYPE_SEARCH_ZEROHIT, op -> { + op.size(pager.getPageSize()); + }, null); + }); + final Terms agg = list.getAggregations().get(SearchLogPager.LOG_TYPE_SEARCH_ZEROHIT); + final List buckets = agg.getBuckets(); + updatePagerByAgg(pager, buckets.size()); + return buckets.stream().map(e -> { + final Map map = new HashMap<>(); + map.put(ID, Base64.getUrlEncoder().encodeToString(e.getKeyAsString().getBytes(StandardCharsets.UTF_8))); + map.put(KEY, e.getKeyAsString()); + map.put(COUNT, e.getDocCount()); + return map; + }).collect(Collectors.toList()); + // } else if (SearchLogPager.LOG_TYPE_SEARCH_ZEROCLICK.equalsIgnoreCase(pager.logType)) { + // list = (EsPagingResultBean) searchLogBhv.selectPage(cb -> { + // cb.fetchFirst(0); + // createSearchLogCondition(pager, cb); + // // TODO 0 clicked + // }); } else { - list = searchLogBhv.selectPage(cb -> { + list = (EsPagingResultBean) searchLogBhv.selectPage(cb -> { cb.paging(pager.getPageSize(), pager.getCurrentPageNumber()); cb.query().addOrderBy_RequestedAt_Desc(); - if (StringUtil.isNotBlank(pager.queryId)) { - cb.query().setQueryId_Term(pager.queryId); - } - if (StringUtil.isNotBlank(pager.userSessionId)) { - cb.query().setUserSessionId_Term(pager.userSessionId); - } - if (StringUtil.isNotBlank(pager.accessType)) { - cb.query().setAccessType_Term(pager.accessType); - } - if (StringUtil.isNotBlank(pager.requestedTimeRange)) { - String[] values = pager.requestedTimeRange.split(" - "); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); - try { - if (values.length > 0) { - cb.query().setRequestedAt_GreaterEqual(parseDateTime(values[0], formatter)); - } - if (values.length > 1) { - cb.query().setRequestedAt_LessEqual(LocalDateTime.parse(values[1], formatter)); - } - } catch (Exception e) { - if (logger.isDebugEnabled()) { - logger.debug("Failed to parse " + pager.requestedTimeRange, e); - } - } - } + createSearchLogCondition(pager, cb); }); } @@ -164,7 +304,94 @@ public class SearchLogService { return list; } - protected LocalDateTime parseDateTime(String value, DateTimeFormatter formatter) { + private void updatePagerByAgg(final SearchLogPager pager, final int size) { + pager.setAllPageCount(1); + pager.setAllRecordCount(size); + pager.setCurrentPageNumber(1); + pager.setExistNextPage(false); + pager.setExistPrePage(false); + pager.setPageSize(pager.getPageSize()); + } + + private void createSearchLogCondition(final SearchLogPager pager, final SearchLogCB cb) { + if (StringUtil.isNotBlank(pager.queryId)) { + cb.query().setQueryId_Term(pager.queryId); + } + if (StringUtil.isNotBlank(pager.userSessionId)) { + cb.query().setUserSessionId_Term(pager.userSessionId); + } + if (StringUtil.isNotBlank(pager.accessType)) { + cb.query().setAccessType_Term(pager.accessType); + } + if (StringUtil.isNotBlank(pager.requestedTimeRange)) { + final String[] values = pager.requestedTimeRange.split(" - "); + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + try { + if (values.length > 0) { + cb.query().setRequestedAt_GreaterEqual(parseDateTime(values[0], formatter)); + } + if (values.length > 1) { + cb.query().setRequestedAt_LessEqual(LocalDateTime.parse(values[1], formatter)); + } + } catch (final Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("Failed to parse " + pager.requestedTimeRange, e); + } + } + } + } + + private void createFavoriteLogCondition(final SearchLogPager pager, final FavoriteLogCB cb) { + if (StringUtil.isNotBlank(pager.queryId)) { + cb.query().setQueryId_Term(pager.queryId); + } + if (StringUtil.isNotBlank(pager.userSessionId)) { + cb.query().setUserInfoId_Term(pager.userSessionId); + } + if (StringUtil.isNotBlank(pager.requestedTimeRange)) { + final String[] values = pager.requestedTimeRange.split(" - "); + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + try { + if (values.length > 0) { + cb.query().setCreatedAt_GreaterEqual(LocalDateTime.parse(values[0], formatter)); + } + if (values.length > 1) { + cb.query().setCreatedAt_LessEqual(parseDateTime(values[1], formatter)); + } + } catch (final Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("Failed to parse " + pager.requestedTimeRange, e); + } + } + } + } + + private void createClickLogCondition(final SearchLogPager pager, final ClickLogCB cb) { + if (StringUtil.isNotBlank(pager.queryId)) { + cb.query().setQueryId_Term(pager.queryId); + } + if (StringUtil.isNotBlank(pager.userSessionId)) { + cb.query().setUserSessionId_Term(pager.userSessionId); + } + if (StringUtil.isNotBlank(pager.requestedTimeRange)) { + final String[] values = pager.requestedTimeRange.split(" - "); + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + try { + if (values.length > 0) { + cb.query().setRequestedAt_GreaterEqual(LocalDateTime.parse(values[0], formatter)); + } + if (values.length > 1) { + cb.query().setRequestedAt_LessEqual(LocalDateTime.parse(values[1], formatter)); + } + } catch (final Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("Failed to parse " + pager.requestedTimeRange, e); + } + } + } + } + + protected LocalDateTime parseDateTime(final String value, final DateTimeFormatter formatter) { return LocalDateTime.parse(value, formatter).atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime(); } diff --git a/src/main/java/org/codelibs/fess/es/config/allcommon/EsSqlClause.java b/src/main/java/org/codelibs/fess/es/config/allcommon/EsSqlClause.java index 22e1d56de..4f8ad7e43 100644 --- a/src/main/java/org/codelibs/fess/es/config/allcommon/EsSqlClause.java +++ b/src/main/java/org/codelibs/fess/es/config/allcommon/EsSqlClause.java @@ -69,4 +69,18 @@ public class EsSqlClause extends AbstractSqlClause { protected String createSqlSuffix() { return null; } + + @Override + public void fetchFirst(int fetchSize) { + _fetchScopeEffective = true; + if (fetchSize < 0) { + String msg = "Argument[fetchSize] should be plus: " + fetchSize; + throw new IllegalArgumentException(msg); + } + _fetchStartIndex = 0; + _fetchSize = fetchSize; + _fetchPageNumber = 1; + doClearFetchPageClause(); + doFetchFirst(); + } } diff --git a/src/main/java/org/codelibs/fess/es/log/allcommon/EsSqlClause.java b/src/main/java/org/codelibs/fess/es/log/allcommon/EsSqlClause.java index 97ebb65a8..7b9efb197 100644 --- a/src/main/java/org/codelibs/fess/es/log/allcommon/EsSqlClause.java +++ b/src/main/java/org/codelibs/fess/es/log/allcommon/EsSqlClause.java @@ -69,4 +69,18 @@ public class EsSqlClause extends AbstractSqlClause { protected String createSqlSuffix() { return null; } + + @Override + public void fetchFirst(int fetchSize) { + _fetchScopeEffective = true; + if (fetchSize < 0) { + String msg = "Argument[fetchSize] should be plus: " + fetchSize; + throw new IllegalArgumentException(msg); + } + _fetchStartIndex = 0; + _fetchSize = fetchSize; + _fetchPageNumber = 1; + doClearFetchPageClause(); + doFetchFirst(); + } } diff --git a/src/main/java/org/codelibs/fess/es/user/allcommon/EsSqlClause.java b/src/main/java/org/codelibs/fess/es/user/allcommon/EsSqlClause.java index b508646d5..82376867b 100644 --- a/src/main/java/org/codelibs/fess/es/user/allcommon/EsSqlClause.java +++ b/src/main/java/org/codelibs/fess/es/user/allcommon/EsSqlClause.java @@ -69,4 +69,18 @@ public class EsSqlClause extends AbstractSqlClause { protected String createSqlSuffix() { return null; } + + @Override + public void fetchFirst(int fetchSize) { + _fetchScopeEffective = true; + if (fetchSize < 0) { + String msg = "Argument[fetchSize] should be plus: " + fetchSize; + throw new IllegalArgumentException(msg); + } + _fetchStartIndex = 0; + _fetchSize = fetchSize; + _fetchPageNumber = 1; + doClearFetchPageClause(); + doFetchFirst(); + } } diff --git a/src/main/java/org/codelibs/fess/mylasta/action/FessLabels.java b/src/main/java/org/codelibs/fess/mylasta/action/FessLabels.java index f84aeb73d..5cd5d9d3b 100644 --- a/src/main/java/org/codelibs/fess/mylasta/action/FessLabels.java +++ b/src/main/java/org/codelibs/fess/mylasta/action/FessLabels.java @@ -2835,12 +2835,45 @@ public class FessLabels extends UserMessages { /** The key of the message: Favorite Log */ public static final String LABELS_searchlog_log_type_favorite = "{labels.searchlog_log_type_favorite}"; + /** The key of the message: Keywords */ + public static final String LABELS_searchlog_log_type_search_keyword = "{labels.searchlog_log_type_search_keyword}"; + + /** The key of the message: Zero Hits */ + public static final String LABELS_searchlog_log_type_search_zerohit = "{labels.searchlog_log_type_search_zerohit}"; + + /** The key of the message: Zero Clicks */ + public static final String LABELS_searchlog_log_type_search_zeroclick = "{labels.searchlog_log_type_search_zeroclick}"; + + /** The key of the message: Keyword by Hour */ + public static final String LABELS_searchlog_log_type_search_count_hour = "{labels.searchlog_log_type_search_count_hour}"; + + /** The key of the message: Keyword by Day */ + public static final String LABELS_searchlog_log_type_search_count_day = "{labels.searchlog_log_type_search_count_day}"; + + /** The key of the message: User by Hour */ + public static final String LABELS_searchlog_log_type_search_user_hour = "{labels.searchlog_log_type_search_user_hour}"; + + /** The key of the message: User by Day */ + public static final String LABELS_searchlog_log_type_search_user_day = "{labels.searchlog_log_type_search_user_day}"; + + /** The key of the message: Request Time Avg. by Hour */ + public static final String LABELS_searchlog_log_type_search_reqtimeavg_hour = "{labels.searchlog_log_type_search_reqtimeavg_hour}"; + + /** The key of the message: Request Time Avg. by Day */ + public static final String LABELS_searchlog_log_type_search_reqtimeavg_day = "{labels.searchlog_log_type_search_reqtimeavg_day}"; + /** The key of the message: Message */ public static final String LABELS_searchlog_log_message = "{labels.searchlog_log_message}"; /** The key of the message: Time */ public static final String LABELS_searchlog_requested_time = "{labels.searchlog_requested_time}"; + /** The key of the message: Value */ + public static final String LABELS_searchlog_value = "{labels.searchlog_value}"; + + /** The key of the message: Count */ + public static final String LABELS_searchlog_count = "{labels.searchlog_count}"; + /** The key of the message: Log Details */ public static final String LABELS_searchlog_configuration_details = "{labels.searchlog_configuration_details}"; diff --git a/src/main/resources/fess_label.properties b/src/main/resources/fess_label.properties index 5794670c0..8948eb0fe 100644 --- a/src/main/resources/fess_label.properties +++ b/src/main/resources/fess_label.properties @@ -936,8 +936,19 @@ labels.searchlog_log_type=Log Type labels.searchlog_log_type_search=Search Log labels.searchlog_log_type_click=Click Log labels.searchlog_log_type_favorite=Favorite Log +labels.searchlog_log_type_search_keyword=Keywords +labels.searchlog_log_type_search_zerohit=Zero Hits +labels.searchlog_log_type_search_zeroclick=Zero Clicks +labels.searchlog_log_type_search_count_hour=Keyword by Hour +labels.searchlog_log_type_search_count_day=Keyword by Day +labels.searchlog_log_type_search_user_hour=User by Hour +labels.searchlog_log_type_search_user_day=User by Day +labels.searchlog_log_type_search_reqtimeavg_hour=Request Time Avg. by Hour +labels.searchlog_log_type_search_reqtimeavg_day=Request Time Avg. by Day labels.searchlog_log_message=Message labels.searchlog_requested_time=Time +labels.searchlog_value=Value +labels.searchlog_count=Count labels.searchlog_configuration_details=Log Details labels.searchlog_configuration_link_top=Search Log labels.searchlog_configuration_link_details=Details diff --git a/src/main/resources/fess_label_en.properties b/src/main/resources/fess_label_en.properties index 4879009c7..268b63de1 100644 --- a/src/main/resources/fess_label_en.properties +++ b/src/main/resources/fess_label_en.properties @@ -936,8 +936,19 @@ labels.searchlog_log_type=Log Type labels.searchlog_log_type_search=Search Log labels.searchlog_log_type_click=Click Log labels.searchlog_log_type_favorite=Favorite Log +labels.searchlog_log_type_search_keyword=Keywords +labels.searchlog_log_type_search_zerohit=Zero Hits +labels.searchlog_log_type_search_zeroclick=Zero Clicks +labels.searchlog_log_type_search_count_hour=Keyword by Hour +labels.searchlog_log_type_search_count_day=Keyword by Day +labels.searchlog_log_type_search_user_hour=User by Hour +labels.searchlog_log_type_search_user_day=User by Day +labels.searchlog_log_type_search_reqtimeavg_hour=Request Time Avg. by Hour +labels.searchlog_log_type_search_reqtimeavg_day=Request Time Avg. by Day labels.searchlog_log_message=Message labels.searchlog_requested_time=Time +labels.searchlog_value=Value +labels.searchlog_count=Count labels.searchlog_configuration_details=Log Details labels.searchlog_configuration_link_top=Search Log labels.searchlog_configuration_link_details=Details diff --git a/src/main/resources/fess_label_ja.properties b/src/main/resources/fess_label_ja.properties index 60ea79de3..3e7da4c61 100644 --- a/src/main/resources/fess_label_ja.properties +++ b/src/main/resources/fess_label_ja.properties @@ -936,8 +936,19 @@ labels.searchlog_log_type=ログ種別 labels.searchlog_log_type_search=検索ログ labels.searchlog_log_type_click=クリックログ labels.searchlog_log_type_favorite=お気に入りログ +labels.searchlog_log_type_search_keyword=キーワード数 +labels.searchlog_log_type_search_zerohit=ゼロ件ヒット数 +labels.searchlog_log_type_search_zeroclick=ゼロ件クリック数 +labels.searchlog_log_type_search_count_hour=検索数/時 +labels.searchlog_log_type_search_count_day=検索数/日 +labels.searchlog_log_type_search_user_hour=ユーザー数/時 +labels.searchlog_log_type_search_user_day=ユーザー数/日 +labels.searchlog_log_type_search_reqtimeavg_hour=リクエスト平均時間/時 +labels.searchlog_log_type_search_reqtimeavg_day=リクエスト平均時間/日 labels.searchlog_log_message=メッセージ labels.searchlog_requested_time=時刻 +labels.searchlog_value=値 +labels.searchlog_count=件数 labels.searchlog_configuration_details=ログ詳細 labels.searchlog_configuration_link_top=検索ログ labels.searchlog_configuration_link_details=詳細 diff --git a/src/main/webapp/WEB-INF/view/admin/searchlog/admin_searchlog.jsp b/src/main/webapp/WEB-INF/view/admin/searchlog/admin_searchlog.jsp index e559c3fd4..d407d6702 100644 --- a/src/main/webapp/WEB-INF/view/admin/searchlog/admin_searchlog.jsp +++ b/src/main/webapp/WEB-INF/view/admin/searchlog/admin_searchlog.jsp @@ -53,6 +53,14 @@ + + + + + + + + @@ -116,20 +124,48 @@ + + + + + + + + + + + + + + + + + + + + + +
${f:h(data.requestedAt)} ${f:h(data.logMessage)}
${f:h(data.key)}${f:h(data.count)}