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.Arrays;
19  import java.util.Map;
20  import java.util.stream.Collectors;
21  
22  import javax.annotation.PostConstruct;
23  
24  import org.apache.logging.log4j.LogManager;
25  import org.apache.logging.log4j.Logger;
26  import org.apache.tika.language.detect.LanguageDetector;
27  import org.apache.tika.language.detect.LanguageResult;
28  import org.codelibs.core.lang.StringUtil;
29  import org.codelibs.fesen.script.Script;
30  import org.codelibs.fess.mylasta.direction.FessConfig;
31  import org.codelibs.fess.util.ComponentUtil;
32  import org.codelibs.fess.util.DocumentUtil;
33  
34  public class LanguageHelper {
35      private static final Logger logger = LogManager.getLogger(LanguageHelper.class);
36  
37      protected String[] langFields;
38  
39      protected String[] supportedLanguages;
40  
41      protected LanguageDetector detector;
42  
43      protected int maxTextLength;
44  
45      @PostConstruct
46      public void init() {
47          if (logger.isDebugEnabled()) {
48              logger.debug("Initialize {}", this.getClass().getSimpleName());
49          }
50          final FessConfig fessConfig = ComponentUtil.getFessConfig();
51          langFields = fessConfig.getIndexerLanguageFieldsAsArray();
52          supportedLanguages = fessConfig.getSupportedLanguagesAsArray();
53          maxTextLength = fessConfig.getIndexerLanguageDetectLengthAsInteger();
54      }
55  
56      public void updateDocument(final Map<String, Object> doc) {
57          final FessConfig fessConfig = ComponentUtil.getFessConfig();
58          String language = getSupportedLanguage(DocumentUtil.getValue(doc, fessConfig.getIndexFieldLang(), String.class));
59          if (language == null) {
60              for (final String f : langFields) {
61                  if (doc.containsKey(f)) {
62                      language = detectLanguage(DocumentUtil.getValue(doc, f, String.class));
63                      if (language != null) {
64                          if (logger.isDebugEnabled()) {
65                              logger.debug("set {} to lang field", language);
66                          }
67                          doc.put(fessConfig.getIndexFieldLang(), language);
68                          break;
69                      }
70                  }
71              }
72              if (language == null) {
73                  return;
74              }
75          }
76  
77          for (final String f : langFields) {
78              final String lf = f + "_" + language;
79              if (doc.containsKey(f) && !doc.containsKey(lf)) {
80                  doc.put(lf, doc.get(f));
81                  if (logger.isDebugEnabled()) {
82                      logger.debug("add {} field", lf);
83                  }
84              }
85          }
86      }
87  
88      protected String detectLanguage(final String text) {
89          if (StringUtil.isBlank(text)) {
90              return null;
91          }
92          final String target = getDetectText(text);
93          final LanguageResult result = detector.detect(target);
94          if (logger.isDebugEnabled()) {
95              logger.debug("detected lang:{}({}) from {}", result, result.getRawScore(), target);
96          }
97          return getSupportedLanguage(result.getLanguage());
98      }
99  
100     protected String getDetectText(final String text) {
101         final String result;
102         if (text.length() <= maxTextLength) {
103             result = text;
104         } else {
105             result = text.substring(0, maxTextLength);
106         }
107         return result.replaceAll("\\s+", " ");
108     }
109 
110     protected String getSupportedLanguage(final String lang) {
111         if (StringUtil.isBlank(lang)) {
112             return null;
113         }
114         for (final String l : supportedLanguages) {
115             if (l.equals(lang)) {
116                 return l;
117             }
118         }
119         return null;
120     }
121 
122     public void setDetector(final LanguageDetector detector) {
123         this.detector = detector;
124     }
125 
126     public Script createScript(final Map<String, Object> doc, final String code) {
127         final StringBuilder buf = new StringBuilder(100);
128         buf.append(code);
129         final FessConfig fessConfig = ComponentUtil.getFessConfig();
130         final String language = DocumentUtil.getValue(doc, fessConfig.getIndexFieldLang(), String.class);
131         if (StringUtil.isNotBlank(language)) {
132             for (final String f : langFields) {
133                 buf.append(";ctx._source.").append(f).append('_').append(language).append("=ctx._source.").append(f);
134             }
135         }
136         if (logger.isDebugEnabled()) {
137             logger.debug("update script: {}", buf);
138         }
139         return new Script(buf.toString());
140     }
141 
142     public String getReindexScriptSource() {
143         final FessConfig fessConfig = ComponentUtil.getFessConfig();
144         final String langField = fessConfig.getIndexFieldLang();
145         final String code = Arrays.stream(langFields).map(s -> "ctx._source['" + s + "_'+ctx._source." + langField + "]=ctx._source." + s)
146                 .collect(Collectors.joining(";"));
147         if (logger.isDebugEnabled()) {
148             logger.debug("reindex script: {}", code);
149         }
150         return "if(ctx._source." + langField + "!=null){" + code + "}";
151     }
152 
153 }