View Javadoc
1   /*
2    * Copyright 2012-2025 CodeLibs Project and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.codelibs.fess.job;
17  
18  import java.util.Map;
19  import java.util.Set;
20  import java.util.stream.Collectors;
21  
22  import org.apache.logging.log4j.LogManager;
23  import org.apache.logging.log4j.Logger;
24  import org.codelibs.core.lang.StringUtil;
25  import org.codelibs.fess.helper.LabelTypeHelper;
26  import org.codelibs.fess.helper.LanguageHelper;
27  import org.codelibs.fess.mylasta.direction.FessConfig;
28  import org.codelibs.fess.opensearch.client.SearchEngineClient;
29  import org.codelibs.fess.util.ComponentUtil;
30  import org.codelibs.fess.util.DocumentUtil;
31  import org.opensearch.index.query.QueryBuilder;
32  import org.opensearch.script.Script;
33  
34  /**
35   * Job class for updating label information in the search index.
36   * This job processes documents and updates their label fields based on URL pattern matching.
37   */
38  public class UpdateLabelJob {
39  
40      private static final Logger logger = LogManager.getLogger(UpdateLabelJob.class);
41  
42      /**
43       * Query builder for filtering documents to be processed.
44       */
45      protected QueryBuilder queryBuilder = null;
46  
47      /**
48       * Default constructor for UpdateLabelJob.
49       */
50      public UpdateLabelJob() {
51          super();
52      }
53  
54      /**
55       * Executes the label update job.
56       * Processes documents in the search index and updates their label fields.
57       *
58       * @return execution result message
59       */
60      public String execute() {
61          final SearchEngineClient searchEngineClient = ComponentUtil.getSearchEngineClient();
62          final FessConfig fessConfig = ComponentUtil.getFessConfig();
63          final LabelTypeHelper labelTypeHelper = ComponentUtil.getLabelTypeHelper();
64          final LanguageHelper languageHelper = ComponentUtil.getLanguageHelper();
65  
66          final StringBuilder resultBuf = new StringBuilder();
67  
68          try {
69              final long count = searchEngineClient.updateByQuery(fessConfig.getIndexDocumentUpdateIndex(), option -> {
70                  if (queryBuilder != null) {
71                      option.setQuery(queryBuilder);
72                  }
73                  return option.setFetchSource(new String[] { fessConfig.getIndexFieldUrl(), fessConfig.getIndexFieldLang() }, null);
74              }, (builder, hit) -> {
75                  try {
76                      final Map<String, Object> doc = hit.getSourceAsMap();
77                      final String url = DocumentUtil.getValue(doc, fessConfig.getIndexFieldUrl(), String.class);
78                      if (StringUtil.isNotBlank(url)) {
79                          final Set<String> labelSet = labelTypeHelper.getMatchedLabelValueSet(url);
80                          final Script script = languageHelper.createScript(doc, "ctx._source." + fessConfig.getIndexFieldLabel()
81                                  + "=new String[]{" + labelSet.stream().map(s -> "\"" + s + "\"").collect(Collectors.joining(",")) + "}");
82                          return builder.setScript(script);
83                      }
84                  } catch (final Exception e) {
85                      logger.warn("Failed to process search hit: {}", hit, e);
86                  }
87                  return null;
88              });
89              resultBuf.append(count).append(" documents").append("\n");
90          } catch (final Exception e) {
91              logger.error("Could not update labels.", e);
92              resultBuf.append(e.getMessage()).append("\n");
93          }
94  
95          return resultBuf.toString();
96      }
97  
98      /**
99       * Sets the query builder for filtering documents.
100      *
101      * @param queryBuilder the query builder to filter documents
102      * @return this UpdateLabelJob instance for method chaining
103      */
104     public UpdateLabelJob query(final QueryBuilder queryBuilder) {
105         this.queryBuilder = queryBuilder;
106         return this;
107     }
108 }