fix #1435 add score updater
This commit is contained in:
parent
786b95df7a
commit
6dd9d20e6b
10 changed files with 505 additions and 16 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -28,3 +28,4 @@
|
|||
dbflute_fess/output/doc/lastadoc-fess.html
|
||||
dbflute_fess/schema/project-lastadoc-fess.json
|
||||
src/main/resources/fess_indices/.fess_config/access_token.bulk
|
||||
src/main/resources/ga_client_secrets.p12
|
||||
|
|
11
pom.xml
11
pom.xml
|
@ -1252,6 +1252,17 @@
|
|||
<artifactId>icu4j</artifactId>
|
||||
<version>60.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.apis</groupId>
|
||||
<artifactId>google-api-services-analyticsreporting</artifactId>
|
||||
<version>v4-rev118-1.23.0</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava-jdk5</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- suggest library -->
|
||||
<dependency>
|
||||
|
|
|
@ -243,7 +243,7 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
/** The key of the configuration. e.g. noscript,script,style,header,footer,nav,a[rel=nofollow] */
|
||||
String CRAWLER_DOCUMENT_HTML_PRUNED_TAGS = "crawler.document.html.pruned.tags";
|
||||
|
||||
/** The key of the configuration. e.g. 200 */
|
||||
/** The key of the configuration. e.g. 120 */
|
||||
String CRAWLER_DOCUMENT_HTML_MAX_DIGEST_LENGTH = "crawler.document.html.max.digest.length";
|
||||
|
||||
/** The key of the configuration. e.g. */
|
||||
|
@ -516,10 +516,10 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
/** The key of the configuration. e.g. true */
|
||||
String QUERY_REPLACE_TERM_WITH_PREFIX_QUERY = "query.replace.term.with.prefix.query";
|
||||
|
||||
/** The key of the configuration. e.g. 50 */
|
||||
/** The key of the configuration. e.g. 40 */
|
||||
String QUERY_HIGHLIGHT_FRAGMENT_SIZE = "query.highlight.fragment.size";
|
||||
|
||||
/** The key of the configuration. e.g. 5 */
|
||||
/** The key of the configuration. e.g. 3 */
|
||||
String QUERY_HIGHLIGHT_NUMBER_OF_FRAGMENTS = "query.highlight.number.of.fragments";
|
||||
|
||||
/** The key of the configuration. e.g. fvh */
|
||||
|
@ -794,10 +794,13 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
/** The key of the configuration. e.g. 100 */
|
||||
String PAGE_THUMBNAIL_PURGE_MAX_FETCH_SIZE = "page.thumbnail.purge.max.fetch.size";
|
||||
|
||||
/** The key of the configuration. e.g. 1000 */
|
||||
String PAGE_SCORE_BOOSTER_MAX_FETCH_SIZE = "page.score.booster.max.fetch.size";
|
||||
|
||||
/** The key of the configuration. e.g. 0 */
|
||||
String PAGING_SEARCH_PAGE_START = "paging.search.page.start";
|
||||
|
||||
/** The key of the configuration. e.g. 20 */
|
||||
/** The key of the configuration. e.g. 10 */
|
||||
String PAGING_SEARCH_PAGE_SIZE = "paging.search.page.size";
|
||||
|
||||
/** The key of the configuration. e.g. 100 */
|
||||
|
@ -1932,14 +1935,14 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
|
||||
/**
|
||||
* Get the value for the key 'crawler.document.html.max.digest.length'. <br>
|
||||
* The value is, e.g. 200 <br>
|
||||
* The value is, e.g. 120 <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getCrawlerDocumentHtmlMaxDigestLength();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'crawler.document.html.max.digest.length' as {@link Integer}. <br>
|
||||
* The value is, e.g. 200 <br>
|
||||
* The value is, e.g. 120 <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
* @throws NumberFormatException When the property is not integer.
|
||||
*/
|
||||
|
@ -2798,14 +2801,14 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
|
||||
/**
|
||||
* Get the value for the key 'query.highlight.fragment.size'. <br>
|
||||
* The value is, e.g. 50 <br>
|
||||
* The value is, e.g. 40 <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getQueryHighlightFragmentSize();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'query.highlight.fragment.size' as {@link Integer}. <br>
|
||||
* The value is, e.g. 50 <br>
|
||||
* The value is, e.g. 40 <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
* @throws NumberFormatException When the property is not integer.
|
||||
*/
|
||||
|
@ -2813,14 +2816,14 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
|
||||
/**
|
||||
* Get the value for the key 'query.highlight.number.of.fragments'. <br>
|
||||
* The value is, e.g. 5 <br>
|
||||
* The value is, e.g. 3 <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getQueryHighlightNumberOfFragments();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'query.highlight.number.of.fragments' as {@link Integer}. <br>
|
||||
* The value is, e.g. 5 <br>
|
||||
* The value is, e.g. 3 <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
* @throws NumberFormatException When the property is not integer.
|
||||
*/
|
||||
|
@ -3862,6 +3865,21 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
*/
|
||||
Integer getPageThumbnailPurgeMaxFetchSizeAsInteger();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'page.score.booster.max.fetch.size'. <br>
|
||||
* The value is, e.g. 1000 <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getPageScoreBoosterMaxFetchSize();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'page.score.booster.max.fetch.size' as {@link Integer}. <br>
|
||||
* The value is, e.g. 1000 <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
* @throws NumberFormatException When the property is not integer.
|
||||
*/
|
||||
Integer getPageScoreBoosterMaxFetchSizeAsInteger();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'paging.search.page.start'. <br>
|
||||
* The value is, e.g. 0 <br>
|
||||
|
@ -3881,14 +3899,14 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
|
||||
/**
|
||||
* Get the value for the key 'paging.search.page.size'. <br>
|
||||
* The value is, e.g. 20 <br>
|
||||
* The value is, e.g. 10 <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
*/
|
||||
String getPagingSearchPageSize();
|
||||
|
||||
/**
|
||||
* Get the value for the key 'paging.search.page.size' as {@link Integer}. <br>
|
||||
* The value is, e.g. 20 <br>
|
||||
* The value is, e.g. 10 <br>
|
||||
* @return The value of found property. (NotNull: if not found, exception but basically no way)
|
||||
* @throws NumberFormatException When the property is not integer.
|
||||
*/
|
||||
|
@ -6759,6 +6777,14 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
return getAsInteger(FessConfig.PAGE_THUMBNAIL_PURGE_MAX_FETCH_SIZE);
|
||||
}
|
||||
|
||||
public String getPageScoreBoosterMaxFetchSize() {
|
||||
return get(FessConfig.PAGE_SCORE_BOOSTER_MAX_FETCH_SIZE);
|
||||
}
|
||||
|
||||
public Integer getPageScoreBoosterMaxFetchSizeAsInteger() {
|
||||
return getAsInteger(FessConfig.PAGE_SCORE_BOOSTER_MAX_FETCH_SIZE);
|
||||
}
|
||||
|
||||
public String getPagingSearchPageStart() {
|
||||
return get(FessConfig.PAGING_SEARCH_PAGE_START);
|
||||
}
|
||||
|
@ -7697,7 +7723,7 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
defaultMap.put(FessConfig.CRAWLER_DOCUMENT_HTML_DIGEST_XPATH, "//META[@name='description']/@content");
|
||||
defaultMap.put(FessConfig.CRAWLER_DOCUMENT_HTML_CANONICAL_XPATH, "//LINK[@rel='canonical']/@href");
|
||||
defaultMap.put(FessConfig.CRAWLER_DOCUMENT_HTML_PRUNED_TAGS, "noscript,script,style,header,footer,nav,a[rel=nofollow]");
|
||||
defaultMap.put(FessConfig.CRAWLER_DOCUMENT_HTML_MAX_DIGEST_LENGTH, "200");
|
||||
defaultMap.put(FessConfig.CRAWLER_DOCUMENT_HTML_MAX_DIGEST_LENGTH, "120");
|
||||
defaultMap.put(FessConfig.CRAWLER_DOCUMENT_FILE_NAME_ENCODING, "");
|
||||
defaultMap.put(FessConfig.CRAWLER_DOCUMENT_FILE_NO_TITLE_LABEL, "No title.");
|
||||
defaultMap.put(FessConfig.CRAWLER_DOCUMENT_FILE_IGNORE_EMPTY_CONTENT, "false");
|
||||
|
@ -7788,8 +7814,8 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
defaultMap.put(FessConfig.QUERY_GEO_FIELDS, "location");
|
||||
defaultMap.put(FessConfig.QUERY_BROWSER_LANG_PARAMETER_NAME, "browser_lang");
|
||||
defaultMap.put(FessConfig.QUERY_REPLACE_TERM_WITH_PREFIX_QUERY, "true");
|
||||
defaultMap.put(FessConfig.QUERY_HIGHLIGHT_FRAGMENT_SIZE, "50");
|
||||
defaultMap.put(FessConfig.QUERY_HIGHLIGHT_NUMBER_OF_FRAGMENTS, "5");
|
||||
defaultMap.put(FessConfig.QUERY_HIGHLIGHT_FRAGMENT_SIZE, "40");
|
||||
defaultMap.put(FessConfig.QUERY_HIGHLIGHT_NUMBER_OF_FRAGMENTS, "3");
|
||||
defaultMap.put(FessConfig.QUERY_HIGHLIGHT_TYPE, "fvh");
|
||||
defaultMap.put(FessConfig.QUERY_MAX_SEARCH_RESULT_OFFSET, "100000");
|
||||
defaultMap.put(FessConfig.QUERY_ADDITIONAL_RESPONSE_FIELDS, "");
|
||||
|
@ -7863,8 +7889,9 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
|
|||
defaultMap.put(FessConfig.PAGE_RELATEDQUERY_MAX_FETCH_SIZE, "5000");
|
||||
defaultMap.put(FessConfig.PAGE_THUMBNAIL_QUEUE_MAX_FETCH_SIZE, "100");
|
||||
defaultMap.put(FessConfig.PAGE_THUMBNAIL_PURGE_MAX_FETCH_SIZE, "100");
|
||||
defaultMap.put(FessConfig.PAGE_SCORE_BOOSTER_MAX_FETCH_SIZE, "1000");
|
||||
defaultMap.put(FessConfig.PAGING_SEARCH_PAGE_START, "0");
|
||||
defaultMap.put(FessConfig.PAGING_SEARCH_PAGE_SIZE, "20");
|
||||
defaultMap.put(FessConfig.PAGING_SEARCH_PAGE_SIZE, "10");
|
||||
defaultMap.put(FessConfig.PAGING_SEARCH_PAGE_MAX_SIZE, "100");
|
||||
defaultMap.put(FessConfig.THUMBNAIL_HTML_PHANTOMJS_ENABLED, "false");
|
||||
defaultMap.put(FessConfig.THUMBNAIL_HTML_PHANTOMJS_MAX_HEIGHT, "20000");
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright 2012-2017 CodeLibs Project and the Others.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language
|
||||
* governing permissions and limitations under the License.
|
||||
*/
|
||||
package org.codelibs.fess.score;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.codelibs.fess.exception.FessSystemException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
|
||||
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.json.GenericJson;
|
||||
import com.google.api.client.json.JsonFactory;
|
||||
import com.google.api.client.json.jackson2.JacksonFactory;
|
||||
import com.google.api.services.analyticsreporting.v4.AnalyticsReporting;
|
||||
import com.google.api.services.analyticsreporting.v4.AnalyticsReportingScopes;
|
||||
import com.google.api.services.analyticsreporting.v4.model.ColumnHeader;
|
||||
import com.google.api.services.analyticsreporting.v4.model.DateRangeValues;
|
||||
import com.google.api.services.analyticsreporting.v4.model.GetReportsRequest;
|
||||
import com.google.api.services.analyticsreporting.v4.model.GetReportsResponse;
|
||||
import com.google.api.services.analyticsreporting.v4.model.MetricHeaderEntry;
|
||||
import com.google.api.services.analyticsreporting.v4.model.Report;
|
||||
import com.google.api.services.analyticsreporting.v4.model.ReportRequest;
|
||||
import com.google.api.services.analyticsreporting.v4.model.ReportRow;
|
||||
|
||||
public class GoogleAnalyticsScoreBooster extends ScoreBooster {
|
||||
private static final Logger logger = LoggerFactory.getLogger(GoogleAnalyticsScoreBooster.class);
|
||||
|
||||
private JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
|
||||
|
||||
private String applicationName = "Fess Score Booster";
|
||||
|
||||
private String keyFileLocation;
|
||||
|
||||
private String serviceAccountEmail;
|
||||
|
||||
private AnalyticsReporting analyticsReporting = null;
|
||||
|
||||
private final Map<String, ReportRequest> reportRequestMap = new HashMap<>();
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (!Paths.get(keyFileLocation).toFile().exists()) {
|
||||
logger.info("GA Key File does not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (reportRequestMap.isEmpty()) {
|
||||
logger.info("No reports.");
|
||||
return;
|
||||
}
|
||||
|
||||
analyticsReporting = initializeAnalyticsReporting();
|
||||
enable();
|
||||
}
|
||||
|
||||
private AnalyticsReporting initializeAnalyticsReporting() {
|
||||
try {
|
||||
final HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
|
||||
final GoogleCredential credential =
|
||||
new GoogleCredential.Builder().setTransport(httpTransport).setJsonFactory(jsonFactory)
|
||||
.setServiceAccountId(serviceAccountEmail).setServiceAccountPrivateKeyFromP12File(new File(keyFileLocation))
|
||||
.setServiceAccountScopes(AnalyticsReportingScopes.all()).build();
|
||||
|
||||
return new AnalyticsReporting.Builder(httpTransport, jsonFactory, credential).setApplicationName(applicationName).build();
|
||||
} catch (final Exception e) {
|
||||
throw new FessSystemException("Failed to initialize GA.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setJsonFactory(final JsonFactory jsonFactory) {
|
||||
this.jsonFactory = jsonFactory;
|
||||
}
|
||||
|
||||
public void setApplicationName(final String applicationName) {
|
||||
this.applicationName = applicationName;
|
||||
}
|
||||
|
||||
public void setKeyFileLocation(final String keyFileLocation) {
|
||||
this.keyFileLocation = keyFileLocation;
|
||||
}
|
||||
|
||||
public void setServiceAccountEmail(final String serviceAccountEmail) {
|
||||
this.serviceAccountEmail = serviceAccountEmail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long process() {
|
||||
long counter = 0;
|
||||
for (final Map.Entry<String, ReportRequest> entry : reportRequestMap.entrySet()) {
|
||||
final GetReportsRequest getReport = new GetReportsRequest().setReportRequests(Arrays.asList(entry.getValue()));
|
||||
try {
|
||||
final GetReportsResponse response = analyticsReporting.reports().batchGet(getReport).execute();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(toPrettyString(response));
|
||||
}
|
||||
for (final Report report : response.getReports()) {
|
||||
final List<ReportRow> rows = report.getData().getRows();
|
||||
final String baseUrl = entry.getKey();
|
||||
if (rows == null) {
|
||||
logger.info("No data found for " + baseUrl);
|
||||
continue;
|
||||
}
|
||||
|
||||
final ColumnHeader header = report.getColumnHeader();
|
||||
final List<String> dimensionHeaders = header.getDimensions();
|
||||
final List<MetricHeaderEntry> metricHeaders = header.getMetricHeader().getMetricHeaderEntries();
|
||||
for (final ReportRow row : rows) {
|
||||
final List<DateRangeValues> metrics = row.getMetrics();
|
||||
for (int j = 0; j < metrics.size(); j++) {
|
||||
String path = null;
|
||||
Long count = null;
|
||||
|
||||
final List<String> dimensions = row.getDimensions();
|
||||
for (int i = 0; i < dimensionHeaders.size() && i < dimensions.size(); i++) {
|
||||
final String name = dimensionHeaders.get(i);
|
||||
if ("ga:pagePath".equals(name)) {
|
||||
path = dimensions.get(i);
|
||||
}
|
||||
}
|
||||
|
||||
final DateRangeValues values = metrics.get(j);
|
||||
for (int k = 0; k < values.getValues().size() && k < metricHeaders.size(); k++) {
|
||||
final String name = metricHeaders.get(k).getName();
|
||||
if ("ga:pageviews".equals(name)) {
|
||||
count = Long.parseLong(values.getValues().get(k));
|
||||
}
|
||||
}
|
||||
|
||||
if (path != null && count != null) {
|
||||
try {
|
||||
final String url = new URL(new URL(baseUrl), path.toString()).toString();
|
||||
final Map<String, Object> params = new HashMap<>();
|
||||
params.put("url", url);
|
||||
params.put("count", count);
|
||||
counter += updateScore(params);
|
||||
} catch (final Exception e) {
|
||||
logger.warn("Invalid url: " + baseUrl + " + " + path, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
logger.warn("Failed to access GA.", e);
|
||||
}
|
||||
}
|
||||
flush();
|
||||
return counter;
|
||||
}
|
||||
|
||||
private String toPrettyString(final GenericJson json) {
|
||||
try {
|
||||
return json.toPrettyString();
|
||||
} catch (final IOException e) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to parse json.", e);
|
||||
}
|
||||
return e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
public void addReportRequest(final String url, final ReportRequest request) {
|
||||
reportRequestMap.put(url, request);
|
||||
}
|
||||
}
|
136
src/main/java/org/codelibs/fess/score/ScoreBooster.java
Normal file
136
src/main/java/org/codelibs/fess/score/ScoreBooster.java
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright 2012-2017 CodeLibs Project and the Others.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language
|
||||
* governing permissions and limitations under the License.
|
||||
*/
|
||||
package org.codelibs.fess.score;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.codelibs.core.lang.StringUtil;
|
||||
import org.codelibs.fess.es.client.FessEsClient;
|
||||
import org.codelibs.fess.mylasta.direction.FessConfig;
|
||||
import org.codelibs.fess.util.ComponentUtil;
|
||||
import org.elasticsearch.action.bulk.BulkRequestBuilder;
|
||||
import org.elasticsearch.action.bulk.BulkResponse;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.action.update.UpdateRequestBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.script.ScriptType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class ScoreBooster {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ScoreBooster.class);
|
||||
|
||||
protected BulkRequestBuilder bulkRequestBuilder = null;
|
||||
|
||||
protected int priority = 1;
|
||||
|
||||
protected String requestTimeout = "1m";
|
||||
|
||||
protected int requestCacheSize = 1000;
|
||||
|
||||
protected String scriptLang = "painless";
|
||||
|
||||
protected String scriptCode = null;
|
||||
|
||||
protected Function<Map<String, Object>, String[]> idFinder = params -> {
|
||||
final FessConfig fessConfig = ComponentUtil.getFessConfig();
|
||||
final FessEsClient client = ComponentUtil.getFessEsClient();
|
||||
final String index = fessConfig.getIndexDocumentUpdateIndex();
|
||||
final Object url = params.get("url");
|
||||
if (url == null) {
|
||||
return StringUtil.EMPTY_STRINGS;
|
||||
}
|
||||
final SearchResponse response =
|
||||
client.prepareSearch(index).setQuery(QueryBuilders.termQuery(fessConfig.getIndexFieldUrl(), url)).setFetchSource(false)
|
||||
.setSize(fessConfig.getPageScoreBoosterMaxFetchSizeAsInteger()).execute().actionGet(requestTimeout);
|
||||
return Arrays.stream(response.getHits().getHits()).map(hit -> hit.getId()).toArray(n -> new String[n]);
|
||||
};
|
||||
|
||||
protected Function<Map<String, Object>, Long> requestHandler = params -> {
|
||||
final FessConfig fessConfig = ComponentUtil.getFessConfig();
|
||||
final String[] ids = idFinder.apply(params);
|
||||
if (ids.length == 0) {
|
||||
return 0L;
|
||||
}
|
||||
final FessEsClient client = ComponentUtil.getFessEsClient();
|
||||
if (bulkRequestBuilder == null) {
|
||||
bulkRequestBuilder = client.prepareBulk();
|
||||
}
|
||||
final String index = fessConfig.getIndexDocumentUpdateIndex();
|
||||
final String type = fessConfig.getIndexDocumentType();
|
||||
for (final String id : ids) {
|
||||
bulkRequestBuilder.add(client.prepareUpdate(index, type, id).setScript(
|
||||
new Script(ScriptType.INLINE, scriptLang, scriptCode, params)));
|
||||
}
|
||||
if (bulkRequestBuilder.numberOfActions() > requestCacheSize) {
|
||||
flush();
|
||||
}
|
||||
return (long) ids.length;
|
||||
};
|
||||
|
||||
public abstract long process();
|
||||
|
||||
protected void enable() {
|
||||
final ScoreUpdater scoreUpdater = ComponentUtil.getComponent("scoreUpdater");
|
||||
scoreUpdater.addScoreBooster(this);
|
||||
}
|
||||
|
||||
protected long updateScore(final Map<String, Object> params) {
|
||||
return requestHandler.apply(params);
|
||||
}
|
||||
|
||||
protected UpdateRequestBuilder createUpdateRequestBuilder() {
|
||||
final FessConfig fessConfig = ComponentUtil.getFessConfig();
|
||||
return ComponentUtil.getFessEsClient().prepareUpdate().setIndex(fessConfig.getIndexDocumentSearchIndex());
|
||||
}
|
||||
|
||||
protected void flush() {
|
||||
if (bulkRequestBuilder != null) {
|
||||
final BulkResponse response = bulkRequestBuilder.execute().actionGet(requestTimeout);
|
||||
if (response.hasFailures()) {
|
||||
logger.warn("Failed to update scores: " + response.buildFailureMessage());
|
||||
}
|
||||
bulkRequestBuilder = null;
|
||||
}
|
||||
}
|
||||
|
||||
public int getPriority() {
|
||||
return this.priority;
|
||||
}
|
||||
|
||||
public void setPriority(final int priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public void setRequestTimeout(final String bulkRequestTimeout) {
|
||||
this.requestTimeout = bulkRequestTimeout;
|
||||
}
|
||||
|
||||
public void setRequestCacheSize(final int requestCacheSize) {
|
||||
this.requestCacheSize = requestCacheSize;
|
||||
}
|
||||
|
||||
public void setScriptLang(final String scriptLang) {
|
||||
this.scriptLang = scriptLang;
|
||||
}
|
||||
|
||||
public void setScriptCode(final String scriptCode) {
|
||||
this.scriptCode = scriptCode;
|
||||
}
|
||||
}
|
47
src/main/java/org/codelibs/fess/score/ScoreUpdater.java
Normal file
47
src/main/java/org/codelibs/fess/score/ScoreUpdater.java
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2012-2017 CodeLibs Project and the Others.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language
|
||||
* governing permissions and limitations under the License.
|
||||
*/
|
||||
package org.codelibs.fess.score;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ScoreUpdater {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ScoreUpdater.class);
|
||||
|
||||
private final List<ScoreBooster> scoreBoosterList = new ArrayList<>();
|
||||
|
||||
public String execute() {
|
||||
final StringBuilder resultBuf = new StringBuilder();
|
||||
scoreBoosterList.forEach(b -> {
|
||||
try {
|
||||
final long count = b.process();
|
||||
resultBuf.append(b.getClass().getSimpleName()).append(" : ").append(count).append('\n');
|
||||
} catch (final Exception e) {
|
||||
logger.warn("Failed to update scores.", e);
|
||||
resultBuf.append(e.getMessage()).append('\n');
|
||||
}
|
||||
});
|
||||
return resultBuf.toString();
|
||||
}
|
||||
|
||||
protected void addScoreBooster(final ScoreBooster scoreBooster) {
|
||||
scoreBoosterList.add(scoreBooster);
|
||||
scoreBoosterList.sort((b1, b2) -> b2.getPriority() - b1.getPriority());
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
<include path="fess_job.xml"/>
|
||||
<include path="fess_thumbnail.xml"/>
|
||||
<include path="fess_sso.xml"/>
|
||||
<include path="fess_score.xml"/>
|
||||
|
||||
<include path="crawler/client.xml" />
|
||||
<include path="crawler/mimetype.xml" />
|
||||
|
|
|
@ -417,6 +417,7 @@ page.relatedcontent.max.fetch.size=5000
|
|||
page.relatedquery.max.fetch.size=5000
|
||||
page.thumbnail.queue.max.fetch.size=100
|
||||
page.thumbnail.purge.max.fetch.size=100
|
||||
page.score.booster.max.fetch.size=1000
|
||||
|
||||
# search page
|
||||
paging.search.page.start=0
|
||||
|
|
|
@ -16,3 +16,5 @@
|
|||
{"name":"Config Reloader","target":"all","cronExpression":"*/10 * * * *","scriptType":"groovy","scriptData":"return container.getComponent(\"systemHelper\").updateConfiguration();","jobLogging":false,"crawler":false,"available":true,"sortOrder":8,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0}
|
||||
{"index":{"_index":".fess_config","_type":"scheduled_job","_id":"ping_es"}}
|
||||
{"name":"Ping Elasticsearch","target":"all","cronExpression":"* * * * *","scriptType":"groovy","scriptData":"return container.getComponent(\"pingEsJob\").execute();","jobLogging":false,"crawler":false,"available":true,"sortOrder":9,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0}
|
||||
{"index":{"_index":".fess_config","_type":"scheduled_job","_id":"score_booster"}}
|
||||
{"name":"Score Updater","target":"all","cronExpression":"0 * * * *","scriptType":"groovy","scriptData":"return container.getComponent(\"scoreUpdater\").execute();","jobLogging":false,"crawler":false,"available":true,"sortOrder":10,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0}
|
||||
|
|
73
src/main/resources/fess_score.xml
Normal file
73
src/main/resources/fess_score.xml
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE components PUBLIC "-//DBFLUTE//DTD LastaDi 1.0//EN"
|
||||
"http://dbflute.org/meta/lastadi10.dtd">
|
||||
<components>
|
||||
<!-- https://developers.google.com/analytics/devguides/reporting/core/v4/ -->
|
||||
<!--
|
||||
<component name="metric1"
|
||||
class="com.google.api.services.analyticsreporting.v4.model.Metric">
|
||||
<postConstruct name="setExpression">
|
||||
<arg>"ga:pageviews"</arg>
|
||||
</postConstruct>
|
||||
</component>
|
||||
<component name="dimension1"
|
||||
class="com.google.api.services.analyticsreporting.v4.model.Dimension">
|
||||
<postConstruct name="setName">
|
||||
<arg>"ga:pagePath"</arg>
|
||||
</postConstruct>
|
||||
</component>
|
||||
<component name="dateRange1"
|
||||
class="com.google.api.services.analyticsreporting.v4.model.DateRange">
|
||||
<postConstruct name="setStartDate">
|
||||
<arg>"7DaysAgo"</arg>
|
||||
</postConstruct>
|
||||
<postConstruct name="setEndDate">
|
||||
<arg>"today"</arg>
|
||||
</postConstruct>
|
||||
</component>
|
||||
<component name="orderBy1"
|
||||
class="com.google.api.services.analyticsreporting.v4.model.OrderBy">
|
||||
<postConstruct name="setFieldName">
|
||||
<arg>"ga:pageviews"</arg>
|
||||
</postConstruct>
|
||||
<postConstruct name="setSortOrder">
|
||||
<arg>"DESCENDING"</arg>
|
||||
</postConstruct>
|
||||
</component>
|
||||
<component name="report1"
|
||||
class="com.google.api.services.analyticsreporting.v4.model.ReportRequest">
|
||||
<postConstruct name="setViewId">
|
||||
<arg>"<REPLACE_WITH_VIEW_ID>"</arg>
|
||||
</postConstruct>
|
||||
<postConstruct name="setMetrics">
|
||||
<arg>[metric1]</arg>
|
||||
</postConstruct>
|
||||
<postConstruct name="setDimensions">
|
||||
<arg>[dimension1]</arg>
|
||||
</postConstruct>
|
||||
<postConstruct name="setDateRanges">
|
||||
<arg>[dateRange1]</arg>
|
||||
</postConstruct>
|
||||
<postConstruct name="setOrderBys">
|
||||
<arg>[orderBy1]</arg>
|
||||
</postConstruct>
|
||||
<postConstruct name="setPageSize">
|
||||
<arg>10000</arg>
|
||||
</postConstruct>
|
||||
</component>
|
||||
<component name="googleAnalyticsScoreBooster" class="org.codelibs.fess.score.GoogleAnalyticsScoreBooster">
|
||||
<property name="keyFileLocation">org.codelibs.core.io.ResourceUtil.getResourceAsFile("ga_client_secrets.p12").getAbsolutePath()
|
||||
</property>
|
||||
<property name="serviceAccountEmail">"<REPLACE_WITH_EMAIL>"</property>
|
||||
<property name="scriptCode">"ctx._source.boost = Math.log(params.count.doubleValue() + 1.0)"</property>
|
||||
<postConstruct name="addReportRequest">
|
||||
<arg>"<BASE_URL>"</arg>
|
||||
<arg>report1</arg>
|
||||
</postConstruct>
|
||||
</component>
|
||||
-->
|
||||
|
||||
<component name="scoreUpdater" class="org.codelibs.fess.score.ScoreUpdater">
|
||||
</component>
|
||||
|
||||
</components>
|
Loading…
Add table
Reference in a new issue