xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/configuration/SuggesterConfig.java (revision 75e99a6911d39f5a39e0c52c3767fa582c4c4ad8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * See LICENSE.txt included in this distribution for the specific
9  * language governing permissions and limitations under the License.
10  *
11  * When distributing Covered Code, include this CDDL HEADER in each
12  * file and include the License file at LICENSE.txt.
13  * If applicable, add the following below this CDDL HEADER, with the
14  * fields enclosed by brackets "[]" replaced with your own identifying
15  * information: Portions Copyright [yyyy] [name of copyright owner]
16  *
17  * CDDL HEADER END
18  */
19 
20 /*
21  * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
22  * Portions Copyright (c) 2019, Chris Fraire <cfraire@me.com>.
23  */
24 package org.opengrok.indexer.configuration;
25 
26 import com.cronutils.model.CronType;
27 import com.cronutils.model.definition.CronDefinitionBuilder;
28 import com.cronutils.parser.CronParser;
29 import org.opengrok.indexer.search.QueryBuilder;
30 
31 import java.util.Arrays;
32 import java.util.HashSet;
33 import java.util.Objects;
34 import java.util.Set;
35 
36 /**
37  * The suggester specific configuration.
38  */
39 public class SuggesterConfig {
40 
41     public static final boolean ENABLED_DEFAULT = true;
42     public static final int MAX_RESULTS_DEFAULT = 10;
43     public static final int MIN_CHARS_DEFAULT = 0;
44     public static final int MAX_PROJECTS_DEFAULT = Short.MAX_VALUE;
45     public static final boolean ALLOW_COMPLEX_QUERIES_DEFAULT = true;
46     public static final boolean ALLOW_MOST_POPULAR_DEFAULT = true;
47     public static final boolean SHOW_SCORES_DEFAULT = false;
48     public static final boolean SHOW_PROJECTS_DEFAULT = true;
49     public static final boolean SHOW_TIME_DEFAULT = false;
50     public static final String REBUILD_CRON_CONFIG_DEFAULT = "0 0 * * *"; // every day at midnight
51     public static final int BUILD_TERMINATION_TIME_DEFAULT = 1800; // half an hour should be enough
52     public static final int TIME_THRESHOLD_DEFAULT = 2000; // 2 sec
53     public static final int REBUILD_THREAD_POOL_PERCENT_NCPUS_DEFAULT = 80;
54 
55     private static final Set<String> allowedProjectsDefault = null;
56     private static final Set<String> allowedFieldsDefault = Set.of(
57             QueryBuilder.FULL,
58             QueryBuilder.DEFS,
59             QueryBuilder.REFS,
60             QueryBuilder.PATH,
61             QueryBuilder.HIST,
62             QueryBuilder.TYPE
63     );
64 
65     /**
66      * Specifies if the suggester is enabled.
67      */
68     private boolean enabled;
69 
70     /**
71      * Specifies maximum number of results suggester should return.
72      */
73     private int maxResults;
74 
75     /**
76      * Specifies minimum number of characters that are needed for suggester to start looking for suggestions.
77      */
78     private int minChars;
79 
80     /**
81      * Specifies set of projects for which the suggester should be enabled. If {@code null} then all projects are
82      * enabled.
83      */
84     private Set<String> allowedProjects;
85 
86     /**
87      * Specifies how many maximum projects can be selected at the same time and the suggestions will work.
88      */
89     private int maxProjects;
90 
91     /**
92      * Specifies the fields for which the suggester should be enabled. If {@code null} then all fields are enabled.
93      */
94     private Set<String> allowedFields;
95 
96     /**
97      * Specifies if the suggester should support complex queries.
98      */
99     private boolean allowComplexQueries;
100 
101     /**
102      * Specifies if the most popular completion should be enabled.
103      */
104     private boolean allowMostPopular;
105 
106     /**
107      * Specifies if the scores should be displayed next to the suggestions.
108      */
109     private boolean showScores;
110 
111     /**
112      * Specifies if the suggestions should show in which project the term was found.
113      */
114     private boolean showProjects;
115 
116     /**
117      * Specifies if the time it took the suggester to find the suggestions should be displayed.
118      */
119     private boolean showTime;
120 
121     /**
122      * Specifies how often should the suggester rebuild the WFST data structures. (Data structures for simple prefix
123      * queries.)
124      */
125     private String rebuildCronConfig;
126 
127     /**
128      * Specifies after how much time (in seconds) the suggester should kill the threads that build the suggester data
129      * structures.
130      */
131     private int buildTerminationTime;
132 
133     /**
134      * Time threshold for suggestions in milliseconds. If the computation exceeds this time,
135      * it will be stopped and partial results will be returned.
136      */
137     private int timeThreshold;
138 
139     /**
140      * Number of threads used for rebuild pool expressed in percent of available CPUs in the system.
141      */
142     private int rebuildThreadPoolSizeInNcpuPercent;
143 
SuggesterConfig()144     public SuggesterConfig() {
145         setEnabled(ENABLED_DEFAULT);
146         setMaxResults(MAX_RESULTS_DEFAULT);
147         setMinChars(MIN_CHARS_DEFAULT);
148         setAllowedProjects(allowedProjectsDefault);
149         setMaxProjects(MAX_PROJECTS_DEFAULT);
150         setAllowedFields(allowedFieldsDefault);
151         setAllowComplexQueries(ALLOW_COMPLEX_QUERIES_DEFAULT);
152         setAllowMostPopular(ALLOW_MOST_POPULAR_DEFAULT);
153         setShowScores(SHOW_SCORES_DEFAULT);
154         setShowProjects(SHOW_PROJECTS_DEFAULT);
155         setShowTime(SHOW_TIME_DEFAULT);
156         setTimeThreshold(TIME_THRESHOLD_DEFAULT);
157         setRebuildCronConfig(REBUILD_CRON_CONFIG_DEFAULT);
158         setBuildTerminationTime(BUILD_TERMINATION_TIME_DEFAULT);
159         setRebuildThreadPoolSizeInNcpuPercent(REBUILD_THREAD_POOL_PERCENT_NCPUS_DEFAULT);
160     }
161 
isEnabled()162     public boolean isEnabled() {
163         return enabled;
164     }
165 
setEnabled(final boolean enabled)166     public void setEnabled(final boolean enabled) {
167         this.enabled = enabled;
168     }
169 
getMaxResults()170     public int getMaxResults() {
171         return maxResults;
172     }
173 
setMaxResults(final int maxResults)174     public void setMaxResults(final int maxResults) {
175         if (maxResults <= 0) {
176             throw new IllegalArgumentException("Max results cannot be negative or zero");
177         }
178         this.maxResults = maxResults;
179     }
180 
getMinChars()181     public int getMinChars() {
182         return minChars;
183     }
184 
setMinChars(final int minChars)185     public void setMinChars(final int minChars) {
186         if (minChars < 0) {
187             throw new IllegalArgumentException(
188                     "Minimum number of characters needed for suggester to provide suggestions cannot be negative");
189         }
190         this.minChars = minChars;
191     }
192 
getAllowedProjects()193     public Set<String> getAllowedProjects() {
194         return allowedProjects;
195     }
196 
setAllowedProjects(final Set<String> allowedProjects)197     public void setAllowedProjects(final Set<String> allowedProjects) {
198         this.allowedProjects = allowedProjects;
199     }
200 
getMaxProjects()201     public int getMaxProjects() {
202         return maxProjects;
203     }
204 
setMaxProjects(final int maxProjects)205     public void setMaxProjects(final int maxProjects) {
206         if (maxProjects < 1) {
207             throw new IllegalArgumentException("Maximum projects for suggestions cannot be less than 1");
208         }
209         this.maxProjects = maxProjects;
210     }
211 
getAllowedFields()212     public Set<String> getAllowedFields() {
213         return allowedFields;
214     }
215 
setAllowedFields(final Set<String> allowedFields)216     public void setAllowedFields(final Set<String> allowedFields) {
217         this.allowedFields = new HashSet<>(allowedFields);
218     }
219 
isAllowComplexQueries()220     public boolean isAllowComplexQueries() {
221         return allowComplexQueries;
222     }
223 
setAllowComplexQueries(final boolean allowComplexQueries)224     public void setAllowComplexQueries(final boolean allowComplexQueries) {
225         this.allowComplexQueries = allowComplexQueries;
226     }
227 
isAllowMostPopular()228     public boolean isAllowMostPopular() {
229         return allowMostPopular;
230     }
231 
setAllowMostPopular(final boolean allowMostPopular)232     public void setAllowMostPopular(final boolean allowMostPopular) {
233         this.allowMostPopular = allowMostPopular;
234     }
235 
isShowScores()236     public boolean isShowScores() {
237         return showScores;
238     }
239 
setShowScores(final boolean showScores)240     public void setShowScores(final boolean showScores) {
241         this.showScores = showScores;
242     }
243 
isShowProjects()244     public boolean isShowProjects() {
245         return showProjects;
246     }
247 
setShowProjects(final boolean showProjects)248     public void setShowProjects(final boolean showProjects) {
249         this.showProjects = showProjects;
250     }
251 
isShowTime()252     public boolean isShowTime() {
253         return showTime;
254     }
255 
setShowTime(final boolean showTime)256     public void setShowTime(final boolean showTime) {
257         this.showTime = showTime;
258     }
259 
getRebuildCronConfig()260     public String getRebuildCronConfig() {
261         return rebuildCronConfig;
262     }
263 
setRebuildCronConfig(final String rebuildCronConfig)264     public void setRebuildCronConfig(final String rebuildCronConfig) {
265         if (rebuildCronConfig != null) { // check cron format
266             CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX));
267             parser.parse(rebuildCronConfig); // throws IllegalArgumentException if invalid
268         }
269         this.rebuildCronConfig = rebuildCronConfig;
270     }
271 
getBuildTerminationTime()272     public int getBuildTerminationTime() {
273         return buildTerminationTime;
274     }
275 
setBuildTerminationTime(final int buildTerminationTime)276     public void setBuildTerminationTime(final int buildTerminationTime) {
277         if (buildTerminationTime < 0) {
278             throw new IllegalArgumentException("Suggester build termination time cannot be negative");
279         }
280         this.buildTerminationTime = buildTerminationTime;
281     }
282 
getTimeThreshold()283     public int getTimeThreshold() {
284         return timeThreshold;
285     }
286 
setTimeThreshold(final int timeThreshold)287     public void setTimeThreshold(final int timeThreshold) {
288         if (timeThreshold < 0) {
289             throw new IllegalArgumentException("Time threshold for suggestions cannot be negative");
290         }
291         this.timeThreshold = timeThreshold;
292     }
293 
setRebuildThreadPoolSizeInNcpuPercent(final int percent)294     public void setRebuildThreadPoolSizeInNcpuPercent(final int percent) {
295         if (percent < 0 || percent > 100) {
296             throw new IllegalArgumentException("Need percentage value");
297         }
298         this.rebuildThreadPoolSizeInNcpuPercent = percent;
299     }
300 
getRebuildThreadPoolSizeInNcpuPercent()301     public int getRebuildThreadPoolSizeInNcpuPercent() {
302         return rebuildThreadPoolSizeInNcpuPercent;
303     }
304 
305     @Override
equals(Object o)306     public boolean equals(Object o) {
307         if (this == o) {
308             return true;
309         }
310         if (o == null || getClass() != o.getClass()) {
311             return false;
312         }
313         SuggesterConfig that = (SuggesterConfig) o;
314         return enabled == that.enabled &&
315                 maxResults == that.maxResults &&
316                 minChars == that.minChars &&
317                 maxProjects == that.maxProjects &&
318                 allowComplexQueries == that.allowComplexQueries &&
319                 allowMostPopular == that.allowMostPopular &&
320                 showScores == that.showScores &&
321                 showProjects == that.showProjects &&
322                 showTime == that.showTime &&
323                 buildTerminationTime == that.buildTerminationTime &&
324                 Objects.equals(allowedProjects, that.allowedProjects) &&
325                 Objects.equals(allowedFields, that.allowedFields) &&
326                 Objects.equals(rebuildCronConfig, that.rebuildCronConfig) &&
327                 rebuildThreadPoolSizeInNcpuPercent == that.rebuildThreadPoolSizeInNcpuPercent;
328     }
329 
330     @Override
hashCode()331     public int hashCode() {
332         return Objects.hash(enabled, maxResults, minChars, allowedProjects, maxProjects, allowedFields,
333                 allowComplexQueries, allowMostPopular, showScores, showProjects, showTime, rebuildCronConfig,
334                 buildTerminationTime, rebuildThreadPoolSizeInNcpuPercent);
335     }
336 
337     /**
338      * Gets an instance version suitable for helper documentation by shifting
339      * most default properties slightly.
340      */
getForHelp()341     static SuggesterConfig getForHelp() {
342         SuggesterConfig res = new SuggesterConfig();
343         res.setEnabled(!res.isEnabled());
344         res.setMaxResults(1 + res.getMaxResults());
345         res.setMinChars(1 + res.getMinChars());
346         res.setAllowedProjects(new HashSet<>(Arrays.asList("project-1", "project-2")));
347         res.setMaxProjects(1 + res.getMaxProjects());
348         res.setAllowedFields(getAllowedFieldsForHelp(res.getAllowedFields()));
349         res.setAllowComplexQueries(!res.isAllowComplexQueries());
350         res.setAllowMostPopular(!res.isAllowMostPopular());
351         res.setShowScores(!res.isShowScores());
352         res.setShowProjects(!res.isShowProjects());
353         res.setShowTime(!res.isShowTime());
354         res.setTimeThreshold(1 + res.getTimeThreshold());
355         res.setRebuildCronConfig("1 0 * * *");
356         res.setBuildTerminationTime(1 + res.getBuildTerminationTime());
357         res.setRebuildThreadPoolSizeInNcpuPercent(1 + res.getRebuildThreadPoolSizeInNcpuPercent());
358         return res;
359     }
360 
getAllowedFieldsForHelp(Set<String> allowedFields)361     private static HashSet<String> getAllowedFieldsForHelp(Set<String> allowedFields) {
362         HashSet<String> res = new HashSet<>(allowedFields);
363         res.remove(QueryBuilder.FULL);
364         return res;
365     }
366 }
367