Skip to content

Commit

Permalink
Refactor Shared Settings, Introduce Dynamic Forecast Settings, Rename (
Browse files Browse the repository at this point in the history
…#912)

* Refactor Shared Settings, Introduce Dynamic Forecast Settings, and Rename Checkpoint mapping File

This commit has undertaken three changes:
* Refactoring of Shared Settings: I've performed a refactoring to unify the settings that are shared between the AD and forecasting modules.
* Introduction of Dynamic Forecast Settings: To increase the adaptability of our system, I've implemented dynamic forecast settings. These settings mirror the existing structure of the AD dynamic settings and will enable us to adjust forecast settings on-the-fly.
* Renaming of Checkpoint File: To enhance the consistency across our AD mapping files, I've renamed checkpoint.json to anomaly-checkpoint.java.

Testing done:
1. added tests for new settings.

Signed-off-by: Kaituo Li <[email protected]>

* name change and delete files

Signed-off-by: Kaituo Li <[email protected]>

---------

Signed-off-by: Kaituo Li <[email protected]>
  • Loading branch information
kaituo authored Jun 1, 2023
1 parent 04ab91e commit 472868d
Show file tree
Hide file tree
Showing 64 changed files with 950 additions and 305 deletions.
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -668,8 +668,9 @@ List<String> jacocoExclusions = [
'org.opensearch.ad.constant.*',
'org.opensearch.forecast.constant.*',
'org.opensearch.timeseries.constant.*',
'org.opensearch.timeseries.settings.TimeSeriesSettings',
'org.opensearch.forecast.settings.ForecastSettings',

//'org.opensearch.ad.common.exception.AnomalyDetectionException',
'org.opensearch.ad.util.ClientUtil',

'org.opensearch.ad.transport.CronRequest',
Expand Down
34 changes: 17 additions & 17 deletions src/main/java/org/opensearch/ad/AnomalyDetectorPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@
import org.opensearch.ad.rest.RestSearchTopAnomalyResultAction;
import org.opensearch.ad.rest.RestStatsAnomalyDetectorAction;
import org.opensearch.ad.rest.RestValidateAnomalyDetectorAction;
import org.opensearch.ad.settings.ADEnabledSetting;
import org.opensearch.ad.settings.ADNumericSetting;
import org.opensearch.ad.settings.AnomalyDetectorSettings;
import org.opensearch.ad.settings.EnabledSetting;
import org.opensearch.ad.settings.LegacyOpenDistroAnomalyDetectorSettings;
import org.opensearch.ad.settings.NumericSetting;
import org.opensearch.ad.stats.ADStat;
import org.opensearch.ad.stats.ADStats;
import org.opensearch.ad.stats.suppliers.CounterSupplier;
Expand Down Expand Up @@ -323,8 +323,8 @@ public Collection<Object> createComponents(
IndexNameExpressionResolver indexNameExpressionResolver,
Supplier<RepositoriesService> repositoriesServiceSupplier
) {
EnabledSetting.getInstance().init(clusterService);
NumericSetting.getInstance().init(clusterService);
ADEnabledSetting.getInstance().init(clusterService);
ADNumericSetting.getInstance().init(clusterService);
this.client = client;
this.threadPool = threadPool;
Settings settings = environment.settings();
Expand Down Expand Up @@ -847,8 +847,8 @@ public List<ExecutorBuilder<?>> getExecutorBuilders(Settings settings) {

@Override
public List<Setting<?>> getSettings() {
List<Setting<?>> enabledSetting = EnabledSetting.getInstance().getSettings();
List<Setting<?>> numericSetting = NumericSetting.getInstance().getSettings();
List<Setting<?>> enabledSetting = ADEnabledSetting.getInstance().getSettings();
List<Setting<?>> numericSetting = ADNumericSetting.getInstance().getSettings();

List<Setting<?>> systemSetting = ImmutableList
.of(
Expand All @@ -873,8 +873,8 @@ public List<Setting<?>> getSettings() {
AnomalyDetectorSettings.MAX_RETRY_FOR_UNRESPONSIVE_NODE,
AnomalyDetectorSettings.COOLDOWN_MINUTES,
AnomalyDetectorSettings.BACKOFF_MINUTES,
AnomalyDetectorSettings.BACKOFF_INITIAL_DELAY,
AnomalyDetectorSettings.MAX_RETRY_FOR_BACKOFF,
AnomalyDetectorSettings.AD_BACKOFF_INITIAL_DELAY,
AnomalyDetectorSettings.AD_MAX_RETRY_FOR_BACKOFF,
// result index rollover
LegacyOpenDistroAnomalyDetectorSettings.AD_RESULT_HISTORY_ROLLOVER_PERIOD,
LegacyOpenDistroAnomalyDetectorSettings.AD_RESULT_HISTORY_MAX_DOCS,
Expand All @@ -891,8 +891,8 @@ public List<Setting<?>> getSettings() {
AnomalyDetectorSettings.MODEL_MAX_SIZE_PERCENTAGE,
AnomalyDetectorSettings.MAX_SINGLE_ENTITY_ANOMALY_DETECTORS,
AnomalyDetectorSettings.MAX_MULTI_ENTITY_ANOMALY_DETECTORS,
AnomalyDetectorSettings.INDEX_PRESSURE_SOFT_LIMIT,
AnomalyDetectorSettings.INDEX_PRESSURE_HARD_LIMIT,
AnomalyDetectorSettings.AD_INDEX_PRESSURE_SOFT_LIMIT,
AnomalyDetectorSettings.AD_INDEX_PRESSURE_HARD_LIMIT,
AnomalyDetectorSettings.MAX_PRIMARY_SHARDS,
// Security
LegacyOpenDistroAnomalyDetectorSettings.FILTER_BY_BACKEND_ROLES,
Expand All @@ -910,21 +910,21 @@ public List<Setting<?>> getSettings() {
AnomalyDetectorSettings.MAX_RUNNING_ENTITIES_PER_DETECTOR_FOR_HISTORICAL_ANALYSIS,
AnomalyDetectorSettings.MAX_CACHED_DELETED_TASKS,
// rate limiting
AnomalyDetectorSettings.CHECKPOINT_READ_QUEUE_CONCURRENCY,
AnomalyDetectorSettings.CHECKPOINT_WRITE_QUEUE_CONCURRENCY,
AnomalyDetectorSettings.AD_CHECKPOINT_READ_QUEUE_CONCURRENCY,
AnomalyDetectorSettings.AD_CHECKPOINT_WRITE_QUEUE_CONCURRENCY,
AnomalyDetectorSettings.ENTITY_COLD_START_QUEUE_CONCURRENCY,
AnomalyDetectorSettings.RESULT_WRITE_QUEUE_CONCURRENCY,
AnomalyDetectorSettings.CHECKPOINT_READ_QUEUE_BATCH_SIZE,
AnomalyDetectorSettings.CHECKPOINT_WRITE_QUEUE_BATCH_SIZE,
AnomalyDetectorSettings.RESULT_WRITE_QUEUE_BATCH_SIZE,
AnomalyDetectorSettings.AD_RESULT_WRITE_QUEUE_CONCURRENCY,
AnomalyDetectorSettings.AD_CHECKPOINT_READ_QUEUE_BATCH_SIZE,
AnomalyDetectorSettings.AD_CHECKPOINT_WRITE_QUEUE_BATCH_SIZE,
AnomalyDetectorSettings.AD_RESULT_WRITE_QUEUE_BATCH_SIZE,
AnomalyDetectorSettings.COLD_ENTITY_QUEUE_MAX_HEAP_PERCENT,
AnomalyDetectorSettings.CHECKPOINT_READ_QUEUE_MAX_HEAP_PERCENT,
AnomalyDetectorSettings.CHECKPOINT_WRITE_QUEUE_MAX_HEAP_PERCENT,
AnomalyDetectorSettings.RESULT_WRITE_QUEUE_MAX_HEAP_PERCENT,
AnomalyDetectorSettings.CHECKPOINT_MAINTAIN_QUEUE_MAX_HEAP_PERCENT,
AnomalyDetectorSettings.ENTITY_COLD_START_QUEUE_MAX_HEAP_PERCENT,
AnomalyDetectorSettings.EXPECTED_COLD_ENTITY_EXECUTION_TIME_IN_MILLISECS,
AnomalyDetectorSettings.EXPECTED_CHECKPOINT_MAINTAIN_TIME_IN_MILLISECS,
AnomalyDetectorSettings.AD_EXPECTED_CHECKPOINT_MAINTAIN_TIME_IN_MILLISECS,
AnomalyDetectorSettings.CHECKPOINT_SAVING_FREQ,
AnomalyDetectorSettings.CHECKPOINT_TTL,
// query limit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@
import org.opensearch.ad.model.DetectorState;
import org.opensearch.ad.model.InitProgressProfile;
import org.opensearch.ad.model.IntervalTimeConfiguration;
import org.opensearch.ad.settings.ADNumericSetting;
import org.opensearch.ad.settings.AnomalyDetectorSettings;
import org.opensearch.ad.settings.NumericSetting;
import org.opensearch.ad.task.ADTaskManager;
import org.opensearch.ad.transport.ProfileAction;
import org.opensearch.ad.transport.ProfileRequest;
Expand Down Expand Up @@ -285,7 +285,7 @@ private void prepareProfile(

private void profileEntityStats(MultiResponsesDelegateActionListener<DetectorProfile> listener, AnomalyDetector detector) {
List<String> categoryField = detector.getCategoryField();
if (!detector.isMultientityDetector() || categoryField.size() > NumericSetting.maxCategoricalFields()) {
if (!detector.isMultientityDetector() || categoryField.size() > ADNumericSetting.maxCategoricalFields()) {
listener.onResponse(new DetectorProfile.Builder().build());
} else {
if (categoryField.size() == 1) {
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/opensearch/ad/EntityProfileRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
import org.opensearch.ad.model.EntityState;
import org.opensearch.ad.model.InitProgressProfile;
import org.opensearch.ad.model.IntervalTimeConfiguration;
import org.opensearch.ad.settings.NumericSetting;
import org.opensearch.ad.settings.ADNumericSetting;
import org.opensearch.ad.transport.EntityProfileAction;
import org.opensearch.ad.transport.EntityProfileRequest;
import org.opensearch.ad.transport.EntityProfileResponse;
Expand Down Expand Up @@ -106,7 +106,7 @@ public void profile(
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser);
AnomalyDetector detector = AnomalyDetector.parse(parser, detectorId);
List<String> categoryFields = detector.getCategoryField();
int maxCategoryFields = NumericSetting.maxCategoricalFields();
int maxCategoryFields = ADNumericSetting.maxCategoricalFields();
if (categoryFields == null || categoryFields.size() == 0) {
listener.onFailure(new IllegalArgumentException(NOT_HC_DETECTOR_ERR_MSG));
} else if (categoryFields.size() > maxCategoryFields) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.opensearch.ad.settings.EnabledSetting;
import org.opensearch.ad.settings.ADEnabledSetting;
import org.opensearch.monitor.jvm.JvmService;

/**
Expand Down Expand Up @@ -76,7 +76,7 @@ public ADCircuitBreakerService init() {
}

public Boolean isOpen() {
if (!EnabledSetting.isADBreakerEnabled()) {
if (!ADEnabledSetting.isADBreakerEnabled()) {
return false;
}

Expand Down
14 changes: 7 additions & 7 deletions src/main/java/org/opensearch/ad/caching/PriorityCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@
import org.opensearch.ad.model.ModelProfile;
import org.opensearch.ad.ratelimit.CheckpointMaintainWorker;
import org.opensearch.ad.ratelimit.CheckpointWriteWorker;
import org.opensearch.ad.settings.AnomalyDetectorSettings;
import org.opensearch.ad.settings.EnabledSetting;
import org.opensearch.ad.settings.ADEnabledSetting;
import org.opensearch.ad.util.DateUtils;
import org.opensearch.cluster.service.ClusterService;
import org.opensearch.common.settings.Setting;
Expand All @@ -63,6 +62,7 @@
import org.opensearch.core.common.Strings;
import org.opensearch.threadpool.ThreadPool;
import org.opensearch.timeseries.constant.CommonMessages;
import org.opensearch.timeseries.settings.TimeSeriesSettings;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
Expand Down Expand Up @@ -162,16 +162,16 @@ public ModelState<EntityModel> get(String modelId, AnomalyDetector detector) {

// during maintenance period, stop putting new entries
if (!maintenanceLock.isLocked() && modelState == null) {
if (EnabledSetting.isDoorKeeperInCacheEnabled()) {
if (ADEnabledSetting.isDoorKeeperInCacheEnabled()) {
DoorKeeper doorKeeper = doorKeepers
.computeIfAbsent(
detectorId,
id -> {
// reset every 60 intervals
return new DoorKeeper(
AnomalyDetectorSettings.DOOR_KEEPER_FOR_CACHE_MAX_INSERTION,
AnomalyDetectorSettings.DOOR_KEEPER_FAULSE_POSITIVE_RATE,
detector.getDetectionIntervalDuration().multipliedBy(AnomalyDetectorSettings.DOOR_KEEPER_MAINTENANCE_FREQ),
TimeSeriesSettings.DOOR_KEEPER_FOR_CACHE_MAX_INSERTION,
TimeSeriesSettings.DOOR_KEEPER_FALSE_POSITIVE_RATE,
detector.getDetectionIntervalDuration().multipliedBy(TimeSeriesSettings.DOOR_KEEPER_MAINTENANCE_FREQ),
clock
);
}
Expand Down Expand Up @@ -501,7 +501,7 @@ private long getRequiredMemory(AnomalyDetector detector, int numberOfEntity) {
.estimateTRCFModelSize(
dimension,
numberOfTrees,
AnomalyDetectorSettings.REAL_TIME_BOUNDING_BOX_CACHE_RATIO,
TimeSeriesSettings.REAL_TIME_BOUNDING_BOX_CACHE_RATIO,
detector.getShingleSize().intValue(),
true
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
import static org.opensearch.ad.settings.AnomalyDetectorSettings.AD_RESULT_HISTORY_RETENTION_PERIOD;
import static org.opensearch.ad.settings.AnomalyDetectorSettings.AD_RESULT_HISTORY_ROLLOVER_PERIOD;
import static org.opensearch.ad.settings.AnomalyDetectorSettings.ANOMALY_DETECTION_STATE_INDEX_MAPPING_FILE;
import static org.opensearch.ad.settings.AnomalyDetectorSettings.ANOMALY_DETECTORS_INDEX_MAPPING_FILE;
import static org.opensearch.ad.settings.AnomalyDetectorSettings.ANOMALY_DETECTOR_JOBS_INDEX_MAPPING_FILE;
import static org.opensearch.ad.settings.AnomalyDetectorSettings.ANOMALY_RESULTS_INDEX_MAPPING_FILE;
import static org.opensearch.ad.settings.AnomalyDetectorSettings.CHECKPOINT_INDEX_MAPPING_FILE;
import static org.opensearch.ad.settings.AnomalyDetectorSettings.MAX_PRIMARY_SHARDS;
import static org.opensearch.timeseries.constant.CommonMessages.CAN_NOT_FIND_RESULT_INDEX;
import static org.opensearch.timeseries.settings.TimeSeriesSettings.INDEX_MAPPING_FILE;
import static org.opensearch.timeseries.settings.TimeSeriesSettings.JOBS_INDEX_MAPPING_FILE;

import java.io.IOException;
import java.net.URL;
Expand Down Expand Up @@ -238,7 +238,7 @@ private void initResultMapping() throws IOException {
* @throws IOException IOException if mapping file can't be read correctly
*/
public static String getAnomalyDetectorMappings() throws IOException {
URL url = AnomalyDetectionIndices.class.getClassLoader().getResource(ANOMALY_DETECTORS_INDEX_MAPPING_FILE);
URL url = AnomalyDetectionIndices.class.getClassLoader().getResource(INDEX_MAPPING_FILE);
return Resources.toString(url, Charsets.UTF_8);
}

Expand All @@ -260,7 +260,7 @@ public static String getAnomalyResultMappings() throws IOException {
* @throws IOException IOException if mapping file can't be read correctly
*/
public static String getAnomalyDetectorJobMappings() throws IOException {
URL url = AnomalyDetectionIndices.class.getClassLoader().getResource(ANOMALY_DETECTOR_JOBS_INDEX_MAPPING_FILE);
URL url = AnomalyDetectionIndices.class.getClassLoader().getResource(JOBS_INDEX_MAPPING_FILE);
return Resources.toString(url, Charsets.UTF_8);
}

Expand Down
14 changes: 7 additions & 7 deletions src/main/java/org/opensearch/ad/ml/EntityColdStarter.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@
import org.opensearch.ad.model.IntervalTimeConfiguration;
import org.opensearch.ad.ratelimit.CheckpointWriteWorker;
import org.opensearch.ad.ratelimit.RequestPriority;
import org.opensearch.ad.settings.AnomalyDetectorSettings;
import org.opensearch.ad.settings.EnabledSetting;
import org.opensearch.ad.settings.ADEnabledSetting;
import org.opensearch.ad.util.ExceptionUtil;
import org.opensearch.common.settings.Settings;
import org.opensearch.threadpool.ThreadPool;
import org.opensearch.timeseries.dataprocessor.Imputer;
import org.opensearch.timeseries.settings.TimeSeriesSettings;

import com.amazon.randomcutforest.config.Precision;
import com.amazon.randomcutforest.parkservices.ThresholdedRandomCutForest;
Expand Down Expand Up @@ -251,9 +251,9 @@ private void coldStart(
id -> {
// reset every 60 intervals
return new DoorKeeper(
AnomalyDetectorSettings.DOOR_KEEPER_FOR_COLD_STARTER_MAX_INSERTION,
AnomalyDetectorSettings.DOOR_KEEPER_FAULSE_POSITIVE_RATE,
detector.getDetectionIntervalDuration().multipliedBy(AnomalyDetectorSettings.DOOR_KEEPER_MAINTENANCE_FREQ),
TimeSeriesSettings.DOOR_KEEPER_FOR_COLD_STARTER_MAX_INSERTION,
TimeSeriesSettings.DOOR_KEEPER_FALSE_POSITIVE_RATE,
detector.getDetectionIntervalDuration().multipliedBy(TimeSeriesSettings.DOOR_KEEPER_MAINTENANCE_FREQ),
clock
);
}
Expand Down Expand Up @@ -365,7 +365,7 @@ private void trainModelFromDataSegments(
.parallelExecutionEnabled(false)
.compact(true)
.precision(Precision.FLOAT_32)
.boundingBoxCacheFraction(AnomalyDetectorSettings.REAL_TIME_BOUNDING_BOX_CACHE_RATIO)
.boundingBoxCacheFraction(TimeSeriesSettings.REAL_TIME_BOUNDING_BOX_CACHE_RATIO)
// same with dimension for opportunistic memory saving
// Usually, we use it as shingleSize(dimension). When a new point comes in, we will
// look at the point store if there is any overlapping. Say the previously-stored
Expand Down Expand Up @@ -596,7 +596,7 @@ private int calculateColdStartDataSize(List<double[][]> coldStartData) {
*/
private Pair<Integer, Integer> selectRangeParam(AnomalyDetector detector) {
int shingleSize = detector.getShingleSize();
if (EnabledSetting.isInterpolationInColdStartEnabled()) {
if (ADEnabledSetting.isInterpolationInColdStartEnabled()) {
long delta = detector.getDetectorIntervalInMinutes();

int strideLength = defaulStrideLength;
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/org/opensearch/ad/ml/ModelManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import org.opensearch.common.settings.Setting;
import org.opensearch.common.settings.Settings;
import org.opensearch.common.unit.TimeValue;
import org.opensearch.timeseries.settings.TimeSeriesSettings;

import com.amazon.randomcutforest.RandomCutForest;
import com.amazon.randomcutforest.config.Precision;
Expand Down Expand Up @@ -527,7 +528,7 @@ private void trainModelForStep(
.parallelExecutionEnabled(false)
.compact(true)
.precision(Precision.FLOAT_32)
.boundingBoxCacheFraction(AnomalyDetectorSettings.REAL_TIME_BOUNDING_BOX_CACHE_RATIO)
.boundingBoxCacheFraction(TimeSeriesSettings.REAL_TIME_BOUNDING_BOX_CACHE_RATIO)
.shingleSize(detector.getShingleSize())
.anomalyRate(1 - thresholdMinPvalue)
.build();
Expand Down
15 changes: 6 additions & 9 deletions src/main/java/org/opensearch/ad/model/AnomalyDetector.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
import static org.opensearch.ad.constant.ADCommonName.CUSTOM_RESULT_INDEX_PREFIX;
import static org.opensearch.ad.model.AnomalyDetectorType.MULTI_ENTITY;
import static org.opensearch.ad.model.AnomalyDetectorType.SINGLE_ENTITY;
import static org.opensearch.ad.settings.AnomalyDetectorSettings.DEFAULT_SHINGLE_SIZE;
import static org.opensearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
import static org.opensearch.index.query.AbstractQueryBuilder.parseInnerQueryBuilder;
import static org.opensearch.timeseries.constant.CommonMessages.INVALID_CHAR_IN_RESULT_INDEX_NAME;
import static org.opensearch.timeseries.settings.TimeSeriesSettings.DEFAULT_SHINGLE_SIZE;

import java.io.IOException;
import java.time.Duration;
Expand All @@ -33,8 +33,7 @@
import org.opensearch.ad.common.exception.ADValidationException;
import org.opensearch.ad.constant.ADCommonMessages;
import org.opensearch.ad.constant.CommonValue;
import org.opensearch.ad.settings.AnomalyDetectorSettings;
import org.opensearch.ad.settings.NumericSetting;
import org.opensearch.ad.settings.ADNumericSetting;
import org.opensearch.ad.util.ParseUtils;
import org.opensearch.common.ParsingException;
import org.opensearch.common.io.stream.StreamInput;
Expand All @@ -54,6 +53,7 @@
import org.opensearch.timeseries.annotation.Generated;
import org.opensearch.timeseries.constant.CommonMessages;
import org.opensearch.timeseries.constant.CommonName;
import org.opensearch.timeseries.settings.TimeSeriesSettings;

import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
Expand Down Expand Up @@ -191,15 +191,12 @@ public AnomalyDetector(
}
if (invalidShingleSizeRange(shingleSize)) {
throw new ADValidationException(
"Shingle size must be a positive integer no larger than "
+ AnomalyDetectorSettings.MAX_SHINGLE_SIZE
+ ". Got "
+ shingleSize,
"Shingle size must be a positive integer no larger than " + TimeSeriesSettings.MAX_SHINGLE_SIZE + ". Got " + shingleSize,
DetectorValidationIssueType.SHINGLE_SIZE_FIELD,
ValidationAspect.DETECTOR
);
}
int maxCategoryFields = NumericSetting.maxCategoricalFields();
int maxCategoryFields = ADNumericSetting.maxCategoricalFields();
if (categoryFields != null && categoryFields.size() > maxCategoryFields) {
throw new ADValidationException(
CommonMessages.getTooManyCategoricalFieldErr(maxCategoryFields),
Expand Down Expand Up @@ -756,6 +753,6 @@ private static boolean isMultientityDetector(List<String> categoryFields) {
}

public boolean invalidShingleSizeRange(Integer shingleSizeToTest) {
return shingleSizeToTest != null && (shingleSizeToTest < 1 || shingleSizeToTest > AnomalyDetectorSettings.MAX_SHINGLE_SIZE);
return shingleSizeToTest != null && (shingleSizeToTest < 1 || shingleSizeToTest > TimeSeriesSettings.MAX_SHINGLE_SIZE);
}
}
Loading

0 comments on commit 472868d

Please sign in to comment.