diff --git a/whylabs_toolkit/monitor/manager/monitor_setup.py b/whylabs_toolkit/monitor/manager/monitor_setup.py index d71038e..3f714d6 100644 --- a/whylabs_toolkit/monitor/manager/monitor_setup.py +++ b/whylabs_toolkit/monitor/manager/monitor_setup.py @@ -43,6 +43,8 @@ def __init__(self, monitor_id: str, dataset_id: Optional[str] = None, config: Co SeasonalConfig, FrequentStringComparisonConfig, ListComparisonConfig, + ConjunctionConfig, + DisjunctionConfig, ] ] = None self._target_columns: Optional[List[str]] = [] @@ -124,6 +126,8 @@ def config( SeasonalConfig, FrequentStringComparisonConfig, ListComparisonConfig, + ConjunctionConfig, + DisjunctionConfig, ] ]: return self._analyzer_config @@ -139,6 +143,8 @@ def config( SeasonalConfig, FrequentStringComparisonConfig, ListComparisonConfig, + ConjunctionConfig, + DisjunctionConfig, ], ) -> None: self._analyzer_config = config @@ -169,7 +175,7 @@ def is_constraint(self, is_constraint: bool) -> None: raise ValueError("Config must first be set") tags = set(self._analyzer_tags or []) if is_constraint: - if not isinstance(self._analyzer_config, (FixedThresholdsConfig)): + if not isinstance(self._analyzer_config, (FixedThresholdsConfig, ConjunctionConfig, DisjunctionConfig)): raise ValueError("Constraint can only be set with FixedThresholdsConfig") tags.add(TAG_ANALYZER_CONSTRAINT) else: @@ -295,6 +301,8 @@ def __configure_target_matrix(self) -> None: def __set_dataset_matrix_for_dataset_metric(self) -> None: if self._analyzer_config: + if isinstance(self._analyzer_config, (ConjunctionConfig, DisjunctionConfig)): + return None if isinstance(self._analyzer_config.metric, DatasetMetric) and isinstance( self._target_matrix, ColumnMatrix ): diff --git a/whylabs_toolkit/monitor/models/__init__.py b/whylabs_toolkit/monitor/models/__init__.py index 79f365f..cf83c28 100644 --- a/whylabs_toolkit/monitor/models/__init__.py +++ b/whylabs_toolkit/monitor/models/__init__.py @@ -39,6 +39,8 @@ "ColumnListChangeConfig", "SeasonalConfig", "StddevConfig", + "ConjunctionConfig", + "DisjunctionConfig", # targets "DatasetMatrix", "ColumnMatrix", diff --git a/whylabs_toolkit/monitor/models/analyzer/__init__.py b/whylabs_toolkit/monitor/models/analyzer/__init__.py index 1e5f89b..0e3f4f6 100644 --- a/whylabs_toolkit/monitor/models/analyzer/__init__.py +++ b/whylabs_toolkit/monitor/models/analyzer/__init__.py @@ -29,6 +29,8 @@ "ListComparisonConfig", "FrequentStringComparisonConfig", "StddevConfig", + "ConjunctionConfig", + "DisjunctionConfig", # enums "DiffMode", "ThresholdType", diff --git a/whylabs_toolkit/monitor/models/analyzer/algorithms.py b/whylabs_toolkit/monitor/models/analyzer/algorithms.py index 75938f0..3946004 100644 --- a/whylabs_toolkit/monitor/models/analyzer/algorithms.py +++ b/whylabs_toolkit/monitor/models/analyzer/algorithms.py @@ -28,6 +28,8 @@ class AlgorithmType(str, Enum): seasonal = "seasonal" fixed = "fixed" experimental = "experimental" + conjunction = "conjunction" + disjunction = "disjunction" class DatasetMetric(str, Enum): @@ -384,3 +386,21 @@ class DiffConfig(AlgorithmConfig): "the target's metric and the baseline metric. Both of these metrics MUST be in rolled up form", ) baseline: Union[TrailingWindowBaseline, ReferenceProfileId, TimeRangeBaseline, SingleBatchBaseline] + + +class ConjunctionConfig(NoExtrasBaseModel): + """Conjunction (ANDs) composite analyzer joining multiple analyzers.""" + + type: Literal[AlgorithmType.conjunction] = AlgorithmType.conjunction + analyzerIds: List[str] = Field( + description="The corresponding analyzer IDs for the conjunction.", + ) + + +class DisjunctionConfig(NoExtrasBaseModel): + """Disjunction (ORs) composite analyzer joining multiple analyzers.""" + + type: Literal[AlgorithmType.disjunction] = AlgorithmType.disjunction + analyzerIds: List[str] = Field( + description="The corresponding analyzer IDs for the disjunction.", + ) diff --git a/whylabs_toolkit/monitor/models/analyzer/analyzer.py b/whylabs_toolkit/monitor/models/analyzer/analyzer.py index 116f374..93d0973 100644 --- a/whylabs_toolkit/monitor/models/analyzer/analyzer.py +++ b/whylabs_toolkit/monitor/models/analyzer/analyzer.py @@ -18,6 +18,8 @@ FixedThresholdsConfig, SeasonalConfig, StddevConfig, + ConjunctionConfig, + DisjunctionConfig, ) from .targets import ColumnMatrix, DatasetMatrix @@ -111,6 +113,8 @@ class Analyzer(NoExtrasBaseModel): DriftConfig, ComparisonConfig, SeasonalConfig, + ConjunctionConfig, + DisjunctionConfig, ] = Field(description="The configuration map of the analyzer", discriminator="type") class Config: diff --git a/whylabs_toolkit/monitor/schema/schema.json b/whylabs_toolkit/monitor/schema/schema.json index 36a8483..61a254e 100644 --- a/whylabs_toolkit/monitor/schema/schema.json +++ b/whylabs_toolkit/monitor/schema/schema.json @@ -584,6 +584,64 @@ }, "additionalProperties": false }, + "ConjunctionConfig": { + "title": "ConjunctionConfig", + "description": "Conjunction (ANDs) composite analyzer joining multiple analyzers\n ", + "type": "object", + "properties": { + "type": { + "title": "Type", + "enum": [ + "conjunction" + ], + "type": "string" + }, + "analyzerIds": { + "title": "AnalyzerIds", + "description": "The corresponding analyzer IDs for the conjunction.", + "maxItems": 10, + "type": "array", + "items": { + "type": "string", + "pattern": "^[A-Za-z0-9_\\-]+$" + } + } + }, + "required": [ + "type", + "analyzerIds" + ], + "additionalProperties": false + }, + "DisjunctionConfig": { + "title": "DisjunctionConfig", + "description": "Disjunction (ORs) composite analyzer joining multiple analyzers\n ", + "type": "object", + "properties": { + "type": { + "title": "Type", + "enum": [ + "disjunction" + ], + "type": "string" + }, + "analyzerIds": { + "title": "AnalyzerIds", + "description": "The corresponding analyzer IDs for the conjunction.", + "maxItems": 10, + "type": "array", + "items": { + "type": "string", + "pattern": "^[A-Za-z0-9_\\-]+$" + } + } + }, + "required": [ + "type", + "analyzerIds" + ], + "additionalProperties": false + }, "DatasetMetric": { "title": "DatasetMetric", "description": "Metrics that are applicable at the dataset level.", @@ -656,7 +714,7 @@ }, "ThresholdType": { "title": "ThresholdType", - "description": "Threshold Type declaring the upper and lower bound.\n\nBy default an anomaly will be generated when the target is above or below the baseline\nby the specified threshold.\n\nIf its only desirable to alert when the target is above the\nbaseline and not the other way around, specify upper for your ThresholdType.", + "description": "Threshold Type declaring the upper and lower bound.\n\n By default an anomaly will be generated when the target is above or below the baseline\n by the specified threshold.\n\n If its only desirable to alert when the target is above the\n baseline and not the other way around, specify upper for your ThresholdType.\n ", "enum": [ "lower", "upper" @@ -1576,6 +1634,8 @@ "expected", "column_list", "comparison", + "conjunction", + "disjunction", "list_comparison", "frequent_string_comparison", "diff", @@ -1902,6 +1962,8 @@ "discriminator": { "propertyName": "type", "mapping": { + "conjunction": "#/definitions/ConjunctionConfig", + "disjunction": "#/definitions/DisjunctionConfig", "diff": "#/definitions/DiffConfig", "comparison": "#/definitions/ComparisonConfig", "list_comparison": "#/definitions/ListComparisonConfig", @@ -1915,6 +1977,12 @@ } }, "oneOf": [ + { + "$ref": "#/definitions/ConjunctionConfig" + }, + { + "$ref": "#/definitions/DisjunctionConfig" + }, { "$ref": "#/definitions/DiffConfig" },