View Javadoc
1   /*
2    * Copyright 2012-2021 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.helper;
17  
18  import java.util.ArrayList;
19  import java.util.List;
20  import java.util.Map;
21  
22  import org.apache.logging.log4j.LogManager;
23  import org.apache.logging.log4j.Logger;
24  import org.codelibs.fesen.action.search.SearchResponse;
25  import org.codelibs.fesen.index.query.QueryBuilder;
26  import org.codelibs.fesen.index.query.QueryBuilders;
27  import org.codelibs.fess.es.client.SearchEngineClient;
28  import org.codelibs.fess.mylasta.direction.FessConfig;
29  import org.codelibs.fess.thumbnail.ThumbnailManager;
30  import org.codelibs.fess.util.ComponentUtil;
31  import org.codelibs.fess.util.DocList;
32  import org.codelibs.fess.util.MemoryUtil;
33  
34  public class IndexingHelper {
35      private static final Logger logger = LogManager.getLogger(IndexingHelper.class);
36  
37      protected int maxRetryCount = 5;
38  
39      protected int defaultRowSize = 100;
40  
41      protected long requestInterval = 500;
42  
43      public void sendDocuments(final SearchEngineClient searchEngineClient, final DocList docList) {
44          if (docList.isEmpty()) {
45              return;
46          }
47          final FessConfig fessConfig = ComponentUtil.getFessConfig();
48          final long execTime = System.currentTimeMillis();
49          if (logger.isDebugEnabled()) {
50              logger.debug("Sending {} documents to a server.", docList.size());
51          }
52          try {
53              if (fessConfig.isThumbnailCrawlerEnabled()) {
54                  final ThumbnailManager thumbnailManager = ComponentUtil.getThumbnailManager();
55                  docList.stream().forEach(doc -> {
56                      if (!thumbnailManager.offer(doc)) {
57                          if (logger.isDebugEnabled()) {
58                              logger.debug("Removing {} from {}", doc.get(fessConfig.getIndexFieldThumbnail()),
59                                      doc.get(fessConfig.getIndexFieldUrl()));
60                          }
61                          doc.remove(fessConfig.getIndexFieldThumbnail());
62                      }
63                  });
64              }
65              final CrawlingConfigHelper crawlingConfigHelper = ComponentUtil.getCrawlingConfigHelper();
66              synchronized (searchEngineClient) {
67                  deleteOldDocuments(searchEngineClient, docList);
68                  searchEngineClient.addAll(fessConfig.getIndexDocumentUpdateIndex(), docList, (doc, builder) -> {
69                      final String configId = (String) doc.get(fessConfig.getIndexFieldConfigId());
70                      crawlingConfigHelper.getPipeline(configId).ifPresent(s -> builder.setPipeline(s));
71                  });
72              }
73              if (logger.isInfoEnabled()) {
74                  if (docList.getContentSize() > 0) {
75                      logger.info("Sent {} docs (Doc:{process {}ms, send {}ms, size {}}, {})", docList.size(), docList.getProcessingTime(),
76                              (System.currentTimeMillis() - execTime), MemoryUtil.byteCountToDisplaySize(docList.getContentSize()),
77                              MemoryUtil.getMemoryUsageLog());
78                  } else {
79                      logger.info("Sent {}  docs (Doc:{send {}ms}, {})", docList.size(), (System.currentTimeMillis() - execTime),
80                              MemoryUtil.getMemoryUsageLog());
81                  }
82              }
83          } finally {
84              docList.clear();
85          }
86      }
87  
88      private void deleteOldDocuments(final SearchEngineClient searchEngineClient, final DocList docList) {
89          final FessConfig fessConfig = ComponentUtil.getFessConfig();
90  
91          final List<String> docIdList = new ArrayList<>();
92          for (final Map<String, Object> inputDoc : docList) {
93              final Object idValue = inputDoc.get(fessConfig.getIndexFieldId());
94              if (idValue == null) {
95                  continue;
96              }
97  
98              final Object configIdValue = inputDoc.get(fessConfig.getIndexFieldConfigId());
99              if (configIdValue == null) {
100                 continue;
101             }
102 
103             final QueryBuilder queryBuilder = QueryBuilders.boolQuery()
104                     .must(QueryBuilders.termQuery(fessConfig.getIndexFieldUrl(), inputDoc.get(fessConfig.getIndexFieldUrl())))
105                     .filter(QueryBuilders.termQuery(fessConfig.getIndexFieldConfigId(), configIdValue));
106 
107             final List<Map<String, Object>> docs = getDocumentListByQuery(searchEngineClient, queryBuilder,
108                     new String[] { fessConfig.getIndexFieldId(), fessConfig.getIndexFieldDocId() });
109             for (final Map<String, Object> doc : docs) {
110                 final Object oldIdValue = doc.get(fessConfig.getIndexFieldId());
111                 if (!idValue.equals(oldIdValue) && oldIdValue != null) {
112                     final Object oldDocIdValue = doc.get(fessConfig.getIndexFieldDocId());
113                     if (oldDocIdValue != null) {
114                         docIdList.add(oldDocIdValue.toString());
115                     }
116                 }
117             }
118             if (logger.isDebugEnabled()) {
119                 logger.debug("{} => {}", queryBuilder, docs);
120             }
121         }
122         if (!docIdList.isEmpty()) {
123             searchEngineClient.deleteByQuery(fessConfig.getIndexDocumentUpdateIndex(),
124                     QueryBuilders.idsQuery().addIds(docIdList.stream().toArray(n -> new String[n])));
125 
126         }
127     }
128 
129     public boolean updateDocument(final SearchEngineClient searchEngineClient, final String id, final String field, final Object value) {
130         final FessConfig fessConfig = ComponentUtil.getFessConfig();
131         return searchEngineClient.update(fessConfig.getIndexDocumentUpdateIndex(), id, field, value);
132     }
133 
134     public boolean deleteDocument(final SearchEngineClient searchEngineClient, final String id) {
135         final FessConfig fessConfig = ComponentUtil.getFessConfig();
136         return searchEngineClient.delete(fessConfig.getIndexDocumentUpdateIndex(), id);
137     }
138 
139     public long deleteDocumentByUrl(final SearchEngineClient searchEngineClient, final String url) {
140         final FessConfig fessConfig = ComponentUtil.getFessConfig();
141         return searchEngineClient.deleteByQuery(fessConfig.getIndexDocumentUpdateIndex(),
142                 QueryBuilders.termQuery(fessConfig.getIndexFieldUrl(), url));
143     }
144 
145     public long deleteDocumentsByDocId(final SearchEngineClient searchEngineClient, final List<String> docIdList) {
146         final FessConfig fessConfig = ComponentUtil.getFessConfig();
147         return searchEngineClient.deleteByQuery(fessConfig.getIndexDocumentUpdateIndex(),
148                 QueryBuilders.idsQuery().addIds(docIdList.stream().toArray(n -> new String[n])));
149     }
150 
151     public long deleteDocumentByQuery(final SearchEngineClient searchEngineClient, final QueryBuilder queryBuilder) {
152         final FessConfig fessConfig = ComponentUtil.getFessConfig();
153         return searchEngineClient.deleteByQuery(fessConfig.getIndexDocumentUpdateIndex(), queryBuilder);
154     }
155 
156     public Map<String, Object> getDocument(final SearchEngineClient searchEngineClient, final String id, final String[] fields) {
157         final FessConfig fessConfig = ComponentUtil.getFessConfig();
158         return searchEngineClient.getDocument(fessConfig.getIndexDocumentUpdateIndex(), builder -> {
159             builder.setQuery(QueryBuilders.idsQuery().addIds(id));
160             builder.setFetchSource(fields, null);
161             return true;
162         }).orElse(null);
163     }
164 
165     public List<Map<String, Object>> getDocumentListByPrefixId(final SearchEngineClient searchEngineClient, final String id,
166             final String[] fields) {
167         final FessConfig fessConfig = ComponentUtil.getFessConfig();
168         final QueryBuilder queryBuilder = QueryBuilders.prefixQuery(fessConfig.getIndexFieldId(), id);
169         return getDocumentListByQuery(searchEngineClient, queryBuilder, fields);
170     }
171 
172     public void deleteChildDocument(final SearchEngineClient searchEngineClient, final String id) {
173         final FessConfig fessConfig = ComponentUtil.getFessConfig();
174         searchEngineClient.deleteByQuery(fessConfig.getIndexDocumentUpdateIndex(),
175                 QueryBuilders.termQuery(fessConfig.getIndexFieldParentId(), id));
176     }
177 
178     public List<Map<String, Object>> getChildDocumentList(final SearchEngineClient searchEngineClient, final String id,
179             final String[] fields) {
180         final FessConfig fessConfig = ComponentUtil.getFessConfig();
181         final QueryBuilder queryBuilder = QueryBuilders.termQuery(fessConfig.getIndexFieldParentId(), id);
182         return getDocumentListByQuery(searchEngineClient, queryBuilder, fields);
183     }
184 
185     protected List<Map<String, Object>> getDocumentListByQuery(final SearchEngineClient searchEngineClient, final QueryBuilder queryBuilder,
186             final String[] fields) {
187         final FessConfig fessConfig = ComponentUtil.getFessConfig();
188 
189         final SearchResponse countResponse = searchEngineClient.prepareSearch(fessConfig.getIndexDocumentUpdateIndex())
190                 .setQuery(queryBuilder).setSize(0).execute().actionGet(fessConfig.getIndexSearchTimeout());
191         final long numFound = countResponse.getHits().getTotalHits().value;
192         // TODO max threshold
193 
194         return searchEngineClient.getDocumentList(fessConfig.getIndexDocumentUpdateIndex(), requestBuilder -> {
195             requestBuilder.setQuery(queryBuilder).setSize((int) numFound);
196             if (fields != null) {
197                 requestBuilder.setFetchSource(fields, null);
198             }
199             return true;
200         });
201 
202     }
203 
204     public long deleteBySessionId(final String sessionId) {
205         final FessConfig fessConfig = ComponentUtil.getFessConfig();
206         final String index = fessConfig.getIndexDocumentUpdateIndex();
207         final QueryBuilder queryBuilder = QueryBuilders.termQuery(fessConfig.getIndexFieldSegment(), sessionId);
208         return deleteByQueryBuilder(index, queryBuilder);
209     }
210 
211     public long deleteByConfigId(final String configId) {
212         final FessConfig fessConfig = ComponentUtil.getFessConfig();
213         final String index = fessConfig.getIndexDocumentUpdateIndex();
214         final QueryBuilder queryBuilder = QueryBuilders.termQuery(fessConfig.getIndexFieldConfigId(), configId);
215         return deleteByQueryBuilder(index, queryBuilder);
216     }
217 
218     public long deleteByVirtualHost(final String virtualHost) {
219         final FessConfig fessConfig = ComponentUtil.getFessConfig();
220         final String index = fessConfig.getIndexDocumentUpdateIndex();
221         final QueryBuilder queryBuilder = QueryBuilders.termQuery(fessConfig.getIndexFieldVirtualHost(), virtualHost);
222         return deleteByQueryBuilder(index, queryBuilder);
223     }
224 
225     protected long deleteByQueryBuilder(final String index, final QueryBuilder queryBuilder) {
226         final SearchEngineClient searchEngineClient = ComponentUtil.getSearchEngineClient();
227         searchEngineClient.admin().indices().prepareRefresh(index).execute().actionGet();
228         final long numOfDeleted = searchEngineClient.deleteByQuery(index, queryBuilder);
229         logger.info("Deleted {} old docs.", numOfDeleted);
230         return numOfDeleted;
231     }
232 
233     public long calculateDocumentSize(final Map<String, Object> dataMap) {
234         return MemoryUtil.sizeOf(dataMap);
235     }
236 
237     public void setMaxRetryCount(final int maxRetryCount) {
238         this.maxRetryCount = maxRetryCount;
239     }
240 
241     public void setDefaultRowSize(final int defaultRowSize) {
242         this.defaultRowSize = defaultRowSize;
243     }
244 
245     public void setRequestInterval(final long requestInterval) {
246         this.requestInterval = requestInterval;
247     }
248 
249 }