View Javadoc
1   /*
2    * Copyright 2012-2017 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.codelibs.fess.es.client.FessEsClient;
23  import org.codelibs.fess.mylasta.direction.FessConfig;
24  import org.codelibs.fess.thumbnail.ThumbnailManager;
25  import org.codelibs.fess.util.ComponentUtil;
26  import org.codelibs.fess.util.DocList;
27  import org.codelibs.fess.util.MemoryUtil;
28  import org.elasticsearch.action.search.SearchResponse;
29  import org.elasticsearch.index.query.QueryBuilder;
30  import org.elasticsearch.index.query.QueryBuilders;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  public class IndexingHelper {
35      private static final Logger logger = LoggerFactory.getLogger(IndexingHelper.class);
36  
37      public int maxRetryCount = 5;
38  
39      public int defaultRowSize = 100;
40  
41      public long requestInterval = 500;
42  
43      public void sendDocuments(final FessEsClient fessEsClient, final DocList docList) {
44          if (docList.isEmpty()) {
45              return;
46          }
47          final FessConfig fessConfig = ComponentUtil.getFessConfig();
48          if (fessConfig.isResultCollapsed()) {
49              docList.forEach(doc -> {
50                  doc.put("content_minhash", doc.get(fessConfig.getIndexFieldContent()));
51              });
52          }
53          final long execTime = System.currentTimeMillis();
54          if (logger.isDebugEnabled()) {
55              logger.debug("Sending " + docList.size() + " documents to a server.");
56          }
57          try {
58              if (fessConfig.isThumbnailCrawlerEnabled()) {
59                  final ThumbnailManager thumbnailManager = ComponentUtil.getThumbnailManager();
60                  docList.stream().forEach(
61                          doc -> {
62                              if (!thumbnailManager.offer(doc)) {
63                                  if (logger.isDebugEnabled()) {
64                                      logger.debug("Removing " + doc.get(fessConfig.getIndexFieldThumbnail()) + " from "
65                                              + doc.get(fessConfig.getIndexFieldUrl()));
66                                  }
67                                  doc.remove(fessConfig.getIndexFieldThumbnail());
68                              }
69                          });
70              }
71              synchronized (fessEsClient) {
72                  deleteOldDocuments(fessEsClient, docList);
73                  fessEsClient.addAll(fessConfig.getIndexDocumentUpdateIndex(), fessConfig.getIndexDocumentType(), docList);
74              }
75              if (logger.isInfoEnabled()) {
76                  if (docList.getContentSize() > 0) {
77                      logger.info("Sent " + docList.size() + " docs (Doc:{process " + docList.getProcessingTime() + "ms, send "
78                              + (System.currentTimeMillis() - execTime) + "ms, size "
79                              + MemoryUtil.byteCountToDisplaySize(docList.getContentSize()) + "}, " + MemoryUtil.getMemoryUsageLog() + ")");
80                  } else {
81                      logger.info("Sent " + docList.size() + " docs (Doc:{send " + (System.currentTimeMillis() - execTime) + "ms}, "
82                              + MemoryUtil.getMemoryUsageLog() + ")");
83                  }
84              }
85          } finally {
86              docList.clear();
87          }
88      }
89  
90      private void deleteOldDocuments(final FessEsClient fessEsClient, final DocList docList) {
91          final FessConfig fessConfig = ComponentUtil.getFessConfig();
92  
93          final List<String> docIdList = new ArrayList<>();
94          for (final Map<String, Object> inputDoc : docList) {
95              final Object idValue = inputDoc.get(fessConfig.getIndexFieldId());
96              if (idValue == null) {
97                  continue;
98              }
99  
100             final Object configIdValue = inputDoc.get(fessConfig.getIndexFieldConfigId());
101             if (configIdValue == null) {
102                 continue;
103             }
104 
105             final QueryBuilder queryBuilder =
106                     QueryBuilders.boolQuery()
107                             .must(QueryBuilders.termQuery(fessConfig.getIndexFieldUrl(), inputDoc.get(fessConfig.getIndexFieldUrl())))
108                             .filter(QueryBuilders.termQuery(fessConfig.getIndexFieldConfigId(), configIdValue));
109 
110             final List<Map<String, Object>> docs =
111                     getDocumentListByQuery(fessEsClient, queryBuilder,
112                             new String[] { fessConfig.getIndexFieldId(), fessConfig.getIndexFieldDocId() });
113             for (final Map<String, Object> doc : docs) {
114                 final Object oldIdValue = doc.get(fessConfig.getIndexFieldId());
115                 if (!idValue.equals(oldIdValue) && oldIdValue != null) {
116                     final Object oldDocIdValue = doc.get(fessConfig.getIndexFieldDocId());
117                     if (oldDocIdValue != null) {
118                         docIdList.add(oldDocIdValue.toString());
119                     }
120                 }
121             }
122             if (logger.isDebugEnabled()) {
123                 logger.debug(queryBuilder.toString() + " => " + docs);
124             }
125         }
126         if (!docIdList.isEmpty()) {
127             fessEsClient.deleteByQuery(fessConfig.getIndexDocumentUpdateIndex(), fessConfig.getIndexDocumentType(),
128                     QueryBuilders.idsQuery(fessConfig.getIndexDocumentType()).addIds(docIdList.stream().toArray(n -> new String[n])));
129 
130         }
131     }
132 
133     public boolean updateDocument(final FessEsClient fessEsClient, final String id, final String field, final Object value) {
134         final FessConfig fessConfig = ComponentUtil.getFessConfig();
135         return fessEsClient.update(fessConfig.getIndexDocumentUpdateIndex(), fessConfig.getIndexDocumentType(), id, field, value);
136     }
137 
138     public boolean deleteDocument(final FessEsClient fessEsClient, final String id) {
139         final FessConfig fessConfig = ComponentUtil.getFessConfig();
140         return fessEsClient.delete(fessConfig.getIndexDocumentUpdateIndex(), fessConfig.getIndexDocumentType(), id, 0);
141     }
142 
143     public int deleteDocumentByUrl(final FessEsClient fessEsClient, final String url) {
144         final FessConfig fessConfig = ComponentUtil.getFessConfig();
145         return fessEsClient.deleteByQuery(fessConfig.getIndexDocumentUpdateIndex(), fessConfig.getIndexDocumentType(),
146                 QueryBuilders.termQuery(fessConfig.getIndexFieldUrl(), url));
147     }
148 
149     public int deleteDocumentsByDocId(final FessEsClient fessEsClient, final List<String> docIdList) {
150         final FessConfig fessConfig = ComponentUtil.getFessConfig();
151         return fessEsClient.deleteByQuery(fessConfig.getIndexDocumentUpdateIndex(), fessConfig.getIndexDocumentType(), QueryBuilders
152                 .idsQuery(fessConfig.getIndexDocumentType()).addIds(docIdList.stream().toArray(n -> new String[n])));
153     }
154 
155     public Map<String, Object> getDocument(final FessEsClient fessEsClient, final String id, final String[] fields) {
156         final FessConfig fessConfig = ComponentUtil.getFessConfig();
157         return fessEsClient.getDocument(fessConfig.getIndexDocumentUpdateIndex(), fessConfig.getIndexDocumentType(), builder -> {
158             builder.setQuery(QueryBuilders.idsQuery(fessConfig.getIndexDocumentType()).addIds(id));
159             builder.setFetchSource(fields, null);
160             return true;
161         }).orElse(null);
162     }
163 
164     public List<Map<String, Object>> getDocumentListByPrefixId(final FessEsClient fessEsClient, final String id, final String[] fields) {
165         final FessConfig fessConfig = ComponentUtil.getFessConfig();
166         final QueryBuilder queryBuilder = QueryBuilders.prefixQuery(fessConfig.getIndexFieldId(), id);
167         return getDocumentListByQuery(fessEsClient, queryBuilder, fields);
168     }
169 
170     public void deleteChildDocument(final FessEsClient fessEsClient, final String id) {
171         final FessConfig fessConfig = ComponentUtil.getFessConfig();
172         fessEsClient.deleteByQuery(fessConfig.getIndexDocumentUpdateIndex(), fessConfig.getIndexDocumentType(),
173                 QueryBuilders.termQuery(fessConfig.getIndexFieldParentId(), id));
174     }
175 
176     public List<Map<String, Object>> getChildDocumentList(final FessEsClient fessEsClient, final String id, final String[] fields) {
177         final FessConfig fessConfig = ComponentUtil.getFessConfig();
178         final QueryBuilder queryBuilder = QueryBuilders.termQuery(fessConfig.getIndexFieldParentId(), id);
179         return getDocumentListByQuery(fessEsClient, queryBuilder, fields);
180     }
181 
182     protected List<Map<String, Object>> getDocumentListByQuery(final FessEsClient fessEsClient, final QueryBuilder queryBuilder,
183             final String[] fields) {
184         final FessConfig fessConfig = ComponentUtil.getFessConfig();
185 
186         final SearchResponse countResponse =
187                 fessEsClient.prepareSearch(fessConfig.getIndexDocumentUpdateIndex()).setTypes(fessConfig.getIndexDocumentType())
188                         .setQuery(queryBuilder).setSize(0).execute().actionGet(fessConfig.getIndexSearchTimeout());
189         final long numFound = countResponse.getHits().getTotalHits();
190         // TODO max threshold
191 
192         return fessEsClient.getDocumentList(fessConfig.getIndexDocumentUpdateIndex(), fessConfig.getIndexDocumentType(),
193                 requestBuilder -> {
194                     requestBuilder.setQuery(queryBuilder).setSize((int) numFound);
195                     if (fields != null) {
196                         requestBuilder.setFetchSource(fields, null);
197                     }
198                     return true;
199                 });
200 
201     }
202 }