rule ---- Functions/classes for Rule Engine .. currentmodule:: src.elevaso_spine Overview ^^^^^^^^ The rule module is intended to evaluate rule(s) against record(s) to determine if there are any matches, and which rules matched. This can be useful when you have a list of records and want to perform targeted filtering (potentially complex) for the purposes of segmentation or targeting. The rule is structured in the following format: .. code-block:: json { "CONDITION": { "OPERATOR": { "RECORD_KEY": "VALUE" } } } where CONDITION is either "AND" or "OR" and used to combine multiple operators. The OPERATOR is one of: * ==: Equals * !=: Not Equals * <=: Less than or equal to * >=: Greater than or equal to * <: Less than * >: Greater than * in: Value is in a list of possible values * !in: Value is not in a list of possible values RECORD_KEY is the dictionary key in the list of records to retrieve the value from and value is a single value to compare to. .. note:: If OPERATOR is `in` or `!in`, then VALUE should be a list of values The rules can support layered logic, for example: .. code-block:: python RULE = { "AND": { "OR": { "==": [ { "key1": "test" }, { "key1": None } ] }, { "!=": { "key2": None } } } } This layered logic can continue further to create extremely complex rules as long as it follows the same formatting of CONDITION, OPERATOR, RECORD_KEY, VALUE. To simplify usage, if there is only one OPERATOR, you can exclude the CONDITION. For example: .. code-block:: python RULE = { "==": { "key1": None } } The rule engine will validate the structure of your rules as you add them and raise an error if any are formatted incorrectly. Additionally, you can use the :meth:`elevaso_spine.rule.engine.RuleEngine.explain_rule` to have a specific rule output in simplified terms. engine ^^^^^^ RuleEngine ~~~~~~~~~~ The :meth:`elevaso_spine.rule.engine.RuleEngine` class provides a way to perform evaluation against a set or rules and records. For example, you have multiple records in dictionary format that contain the following keys: 1. record_id 2. first_name 3. last_name 4. state You want to find all individuals with the first name of John living in the state of Utah. Separately, you want to find all the individuals living in the state of Nevada. The rules would look like: .. code-block:: json [ { "rule_num": 1, "rule": { "AND": { "==": [ { "first_name": "John" }, { "state": "Utah" } ] } } }, { "rule_num": 2, "rule": { "==": { "state": "Nevada" } } } ] Your code would look like the following: .. code-block:: python from elevaso_spine.rule.engine import RuleEngine RULES = [ { "rule_num": 1, "rule": { "AND": { "==": [ { "first_name": "John" }, { "state": "Utah" } ] } } }, { "rule_num": 2, "rule": { "==": { "state": "Nevada" } } } ] RECORDS = [ { "record_id": 1, "first_name": "John", "last_name": "Smith", "state": "Utah", }, { "record_id": 2, "first_name": "John", "last_name": "Johnson", "state": "Nevada", }, { "record_id": 3, "first_name": "Jane", "last_name": "Smith", "state": "Nevada", }, ] rule_engine = RuleEngine() rule_engine.add_rule_set(RULES) rule_engine.add_record_set(RECORDS) rule_engine.eval() print(rule_engine.output) This will print the following: .. code-block:: python [ ( { 'record_id': 1, 'first_name': 'John', 'last_name': 'Smith', 'state': 'Utah' }, [1] ), ( { 'record_id': 2, 'first_name': 'John', 'last_name': 'Johnson', 'state': 'Nevada' }, [2] ), ( { 'record_id': 3, 'first_name': 'Jane', 'last_name': 'Smith', 'state': 'Nevada' }, [2] ) ] The output contains a list of tuple results where the tuple contains the original record and a list of rule numbers that match. .. autoclass:: elevaso_spine.rule.engine.RuleEngine :special-members: __init__ :members: operators ^^^^^^^^^ contains ~~~~~~~~~~ The :meth:`elevaso_spine.rule.operators.contains` function checks if the value exists in the values list and supports the :code:`in` operator of rule engine. .. autofunction:: elevaso_spine.rule.operators.contains not_contains ~~~~~~~~~~~~ The :meth:`elevaso_spine.rule.operators.not_contains` function checks if the value exists in the values list and supports the :code:`!in` operator of rule engine. .. autofunction:: elevaso_spine.rule.operators.not_contains