Skip to content

Commit

Permalink
Integrate E-Divisive (Hunter) as a changepoint detection algorithm: F…
Browse files Browse the repository at this point in the history
…ixes Hyperfoil#1007

 - run bulk change detection once per fingerprint
 - Allow option to recalc datapoints for variables, or re-use
 - added end-to-end and injectable tests
 - Disable eDivisive tests unless enabled with 'ci' profile
  • Loading branch information
johnaohara committed Apr 29, 2024
1 parent d93c4e4 commit 51f6d08
Show file tree
Hide file tree
Showing 31 changed files with 1,020 additions and 238 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ jobs:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Install Hunter
run: pipx install git+https://github.com/datastax-labs/hunter.git
- name: Maven Version
run: mvn --version
- name: Build and Test
run: mvn clean install -B --file pom.xml ${{ matrix.os.build-options }}
run: mvn clean install -B --file pom.xml ${{ matrix.os.build-options }} -P ci
- name: Check uncommitted changes
if: matrix.os.name == 'ubuntu-latest'
run: |
Expand Down
26 changes: 26 additions & 0 deletions docs/site/content/en/openapi/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2459,16 +2459,19 @@ components:
oneOf:
- $ref: '#/components/schemas/RelativeDifferenceDetectionConfig'
- $ref: '#/components/schemas/FixedThresholdDetectionConfig'
- $ref: '#/components/schemas/EDivisiveDetectionConfig'
discriminator:
propertyName: model
mapping:
relativeDifference: '#/components/schemas/RelativeDifferenceDetectionConfig'
fixedThreshold: '#/components/schemas/FixedThresholdDetectionConfig'
eDivisive: '#/components/schemas/EDivisiveDetectionConfig'
ChangeDetectionModelType:
description: Type of Change Detection Model
enum:
- FIXED_THRESHOLD
- RELATIVE_DIFFERENCE
- EDIVISIVE
type: string
ComparisonResult:
description: Result of performing a Comparison
Expand Down Expand Up @@ -2806,6 +2809,19 @@ components:
- ELASTICSEARCH
type: string
example: ELASTICSEARCH
EDivisiveDetectionConfig:
required:
- builtIn
- model
type: object
properties:
builtIn:
description: Built In
type: boolean
model:
enum:
- eDivisive
type: string
ElasticsearchDatastoreConfig:
description: Type of backend datastore
required:
Expand Down Expand Up @@ -3079,13 +3095,18 @@ components:
FixedThresholdDetectionConfig:
required:
- builtIn
- model
- min
- max
type: object
properties:
builtIn:
description: Built In
type: boolean
model:
enum:
- fixedThreshold
type: string
min:
description: Lower bound for acceptable datapoint values
type: object
Expand Down Expand Up @@ -3514,6 +3535,7 @@ components:
RelativeDifferenceDetectionConfig:
required:
- builtIn
- model
- filter
- window
- threshold
Expand All @@ -3523,6 +3545,10 @@ components:
builtIn:
description: Built In
type: boolean
model:
enum:
- relativeDifference
type: string
filter:
description: Relative Difference Detection filter
type: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.hyperfoil.tools.horreum.api.data.changeDetection.ChangeDetectionModelType;
import io.hyperfoil.tools.horreum.api.data.changeDetection.EDivisiveDetectionConfig;
import io.hyperfoil.tools.horreum.api.data.changeDetection.FixedThresholdDetectionConfig;
import io.hyperfoil.tools.horreum.api.data.changeDetection.RelativeDifferenceDetectionConfig;
import jakarta.validation.constraints.NotNull;
Expand All @@ -20,12 +22,14 @@ public class ChangeDetection {
@JsonProperty( required = true )
@Schema(type = SchemaType.OBJECT, discriminatorProperty = "model",
discriminatorMapping = {
@DiscriminatorMapping(schema = RelativeDifferenceDetectionConfig.class, value = "relativeDifference"),
@DiscriminatorMapping(schema = FixedThresholdDetectionConfig.class, value = "fixedThreshold")
@DiscriminatorMapping(schema = RelativeDifferenceDetectionConfig.class, value = ChangeDetectionModelType.names.RELATIVE_DIFFERENCE),
@DiscriminatorMapping(schema = FixedThresholdDetectionConfig.class, value = ChangeDetectionModelType.names.FIXED_THRESHOLD),
@DiscriminatorMapping(schema = EDivisiveDetectionConfig.class, value = ChangeDetectionModelType.names.EDIVISIVE)
},
oneOf = {
RelativeDifferenceDetectionConfig.class,
FixedThresholdDetectionConfig.class
FixedThresholdDetectionConfig.class,
EDivisiveDetectionConfig.class
}
)
public ObjectNode config;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.List;
import java.util.Map;

import io.hyperfoil.tools.horreum.api.data.changeDetection.ChangeDetectionModelType;
import jakarta.validation.constraints.NotNull;

import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
Expand All @@ -16,7 +17,7 @@
@Schema(type = SchemaType.OBJECT, description = "A configuration object for Change detection models")
public class ConditionConfig {
@NotNull
@Schema(description = "Name of Change detection model", example = "fixedThreshold")
@Schema(description = "Name of Change detection model", example = ChangeDetectionModelType.names.FIXED_THRESHOLD)
public String name;
@NotNull
@Schema(description = "UI name for change detection model", example = "Fixed Threshold")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.hyperfoil.tools.horreum.api.data.changeDetection.ChangeDetectionModelType;
import jakarta.validation.constraints.NotNull;
import org.eclipse.microprofile.openapi.annotations.media.Schema;

public class ExperimentComparison {

@NotNull
@JsonProperty( required = true )
@Schema(description = "Name of comparison model", example = "relativeDifference")
@Schema(description = "Name of comparison model", example = ChangeDetectionModelType.names.RELATIVE_DIFFERENCE)
public String model;
@NotNull
@JsonProperty( required = true )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
import org.eclipse.microprofile.openapi.annotations.media.Schema;

import java.util.Arrays;
import java.util.Optional;

@Schema(type = SchemaType.STRING, required = true,
description = "Type of Change Detection Model")
public enum ChangeDetectionModelType {
FIXED_THRESHOLD("fixedThreshold", new TypeReference<FixedThresholdDetectionConfig>() {}),
RELATIVE_DIFFERENCE ("relativeDifference", new TypeReference<RelativeDifferenceDetectionConfig>() {});

FIXED_THRESHOLD(names.FIXED_THRESHOLD, new TypeReference<FixedThresholdDetectionConfig>() {}),
RELATIVE_DIFFERENCE (names.RELATIVE_DIFFERENCE, new TypeReference<RelativeDifferenceDetectionConfig>() {}),
EDIVISIVE(names.EDIVISIVE, new TypeReference<EDivisiveDetectionConfig>() {});
private static final ChangeDetectionModelType[] VALUES = values();

private final String name;
Expand All @@ -32,4 +33,10 @@ public <T extends BaseChangeDetectionConfig> TypeReference<T> getTypeReference()
public static ChangeDetectionModelType fromString(String str) {
return Arrays.stream(VALUES).filter(v -> v.name.equals(str)).findAny().orElseThrow(() -> new IllegalArgumentException("Unknown model: " + str));
}

public static class names {
public static final String FIXED_THRESHOLD = "fixedThreshold";
public static final String RELATIVE_DIFFERENCE = "relativeDifference";
public static final String EDIVISIVE = "eDivisive";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.hyperfoil.tools.horreum.api.data.changeDetection;

import io.hyperfoil.tools.horreum.api.data.datastore.BaseChangeDetectionConfig;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.Schema;

public class EDivisiveDetectionConfig extends BaseChangeDetectionConfig {
@Schema(type = SchemaType.STRING, required = true, enumeration = {ChangeDetectionModelType.names.EDIVISIVE})
public String model;

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
* Concrete configuration type for io.hyperfoil.tools.horreum.changedetection.FixedThresholdModel
*/
public class FixThresholdConfig {
@Schema(type = SchemaType.STRING, required = true, example = "fixedThreshold",
description = "model descriminator")
public static final String model = "fixedThreshold";
@Schema(type = SchemaType.INTEGER, required = true, example = "95",
description = "Threshold Value")
public Double value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@
import org.eclipse.microprofile.openapi.annotations.media.Schema;

public class FixedThresholdDetectionConfig extends BaseChangeDetectionConfig {
@Schema(type = SchemaType.STRING, required = true, enumeration = { ChangeDetectionModelType.names.FIXED_THRESHOLD })
public String model;
@Schema(type = SchemaType.OBJECT, required = true,
description = "Lower bound for acceptable datapoint values")
public FixThresholdConfig min;
@Schema(type = SchemaType.OBJECT, required = true,
description = "Upper bound for acceptable datapoint values")
public FixThresholdConfig max;

@Override
public String validateConfig() {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@
* Concrete configuration type for io.hyperfoil.tools.horreum.changedetection.RelativeDifferenceChangeDetectionModel
*/
public class RelativeDifferenceDetectionConfig extends BaseChangeDetectionConfig {
@Schema(type = SchemaType.STRING, required = true, example = "relativeDifference",
description = "model descriminator")
public static final String model = "relativeDifference";
@Schema(type = SchemaType.STRING, required = true, enumeration = { ChangeDetectionModelType.names.RELATIVE_DIFFERENCE } )
public String model;
@Schema(type = SchemaType.STRING, required = true, example = "mean",
description = "Relative Difference Detection filter")
public String filter;
Expand All @@ -24,8 +23,4 @@ public class RelativeDifferenceDetectionConfig extends BaseChangeDetectionConfi
description = "Minimal number of preceding datapoints")
public Integer minPrevious;

@Override
public String validateConfig() {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,4 @@ public BaseChangeDetectionConfig(Boolean builtIn) {
this.builtIn = builtIn;
}

public abstract String validateConfig();
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ void updateChange(@Parameter(required = true) @PathParam("id") int id,
void recalculateDatapoints(@Parameter(required = true) @QueryParam("test") int testId,
@QueryParam("notify") boolean notify,
@QueryParam("debug") boolean debug,
@QueryParam("clear") Boolean clearDatapoints,
@QueryParam("from") Long from, @QueryParam("to") Long to);

@GET
Expand Down
15 changes: 15 additions & 0 deletions horreum-backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
<packaging>jar</packaging>
<name>Horreum Backend</name>

<properties>
<excludeTags>CiTests</excludeTags>
</properties>



<dependencies>
<dependency>
<groupId>io.hyperfoil.tools</groupId>
Expand Down Expand Up @@ -253,6 +259,7 @@
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<excludedGroups>${excludeTags}</excludedGroups>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
Expand All @@ -276,6 +283,14 @@
</build>

<profiles>

<profile>
<id>ci</id>
<properties>
<excludeTags></excludeTags>
</properties>
</profile>

<profile>
<id>do-release</id>
<properties>
Expand Down
1 change: 1 addition & 0 deletions horreum-backend/src/main/docker/Dockerfile.jvm.base
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
FROM registry.access.redhat.com/ubi9/openjdk-17
COPY src/main/resources/horreum.sh /deployments/
COPY src/main/resources/k8s-setup.sh /deployments/
RUN pipx install git+ssh://[email protected]/datastax-labs/hunter
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ public interface ChangeDetectionModel {

ChangeDetectionModelType type();
void analyze(List<DataPointDAO> dataPoints, JsonNode configuration, Consumer<ChangeDAO> changeConsumer);
ModelType getType();

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,18 @@
@ApplicationScoped
public class FixedThresholdModel implements ChangeDetectionModel {
private static final Logger log = Logger.getLogger(FixedThresholdModel.class);
public static final String NAME = "fixedThreshold";

@Inject
ObjectMapper mapper;

@Override
public ConditionConfig config() {
ConditionConfig conditionConfig = new ConditionConfig(NAME, "Fixed Threshold", "This model checks that the datapoint value is within fixed bounds.")
ConditionConfig conditionConfig = new ConditionConfig(ChangeDetectionModelType.names.FIXED_THRESHOLD, "Fixed Threshold", "This model checks that the datapoint value is within fixed bounds.")
.addComponent("min", new ConditionConfig.NumberBound(), "Minimum", "Lower bound for acceptable datapoint values.")
.addComponent("max", new ConditionConfig.NumberBound(), "Maximum", "Upper bound for acceptable datapoint values.");
conditionConfig.defaults.put("model", new TextNode(NAME));

conditionConfig.defaults.put("model", new TextNode(ChangeDetectionModelType.names.FIXED_THRESHOLD));
return conditionConfig;

}

@Override
Expand Down Expand Up @@ -71,5 +70,8 @@ public void analyze(List<DataPointDAO> dataPoints, JsonNode configuration, Consu

}


@Override
public ModelType getType() {
return ModelType.CONTINOUS;
}
}
Loading

0 comments on commit 51f6d08

Please sign in to comment.