Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/enable and disable rules #1106

Closed
wants to merge 9 commits into from

Conversation

MariusWirtz
Copy link
Collaborator

Successor of #1103

Copy link
Collaborator

@vmitsenko vmitsenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not all tests passed

TM1py/Objects/Cube.py Outdated Show resolved Hide resolved
self.rules.text[:-len(encoded_feeders_statement)] + base64.b64decode(encoded_feeders).decode('utf-8'))

def disable_feeders(self):
if not self.rules:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding a RunTimeError when attempting to disable feeders in a rule without feeders

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a TM1py user, I would prefer not to receive an error in that scenario. If we did raise it, I would have to handle it on each write function just in case that feeders might be removed at some point in the cube.

But that's just my opinion

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with that, just noticed that in this scenario we get
ValueError: 'feeders;' is not in list
which is still easy to interpret

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just pushed another commit. Neither empty rules nor empty feeders will raise an error.

I think that's the most convenient from a user perspective. Especially if we introduce this as an optional argument on the write function.

@MariusWirtz
Copy link
Collaborator Author

@vmitsenko, @nicolasbisurgi
All tests pass.

Are you OK to merge?

self.rules.text[:-len(encoded_feeders_statement)] + base64.b64decode(encoded_feeders).decode('utf-8'))

def disable_feeders(self):
if not self.rules:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with that, just noticed that in this scenario we get
ValueError: 'feeders;' is not in list
which is still easy to interpret

Also handle duplicated disables, enables
@MariusWirtz MariusWirtz force-pushed the feature/enable-and-disable-rules branch from c43abe8 to ccaa004 Compare April 29, 2024 21:12
@MariusWirtz
Copy link
Collaborator Author

The below script attempts to quantify performance improvements in this feature. It is self contained and should work with any environment.

With MTFeeders set to True, I get a 10% performance improvement in a scenario with heavy feeding rules (each written cell feeds 1000 other cells).

@vmitsenko, @nicolasbisurgi
Do you have a more or less optimal scenario in your environment?

from datetime import datetime

import numpy as np
import pandas as pd

from TM1py import TM1Service
from TM1py.Objects.Cube import Cube

tm1params = {...}

CUBE_NAME = "Py Cube"
DIMENSION_NAMES = ["Py Version", "Py Time", "Py Product", "Py Customer", "Py Measure"]
ELEMENTS = [f"Element {str(n).zfill(3)}" for n in range(1, 1001)]
VERSION_VALUE = "Element 001"
NUM_RECORDS = 1_000

with TM1Service(**tm1params) as tm1:
    for dimension_name in DIMENSION_NAMES:
        df = pd.DataFrame(
            columns=[dimension_name],
            data=ELEMENTS)
        df["level000"] = "TOTAL"
        tm1.hierarchies.update_or_create_hierarchy_from_dataframe(
            dimension_name=dimension_name,
            hierarchy_name=dimension_name,
            df=df)

    rules = """
    SKIPCHECK;
    
    FEEDERS;
    ['Py Version':'Element 001'] => ['Py Version':'TOTAL'];
    """
    cube = Cube(CUBE_NAME, dimensions=DIMENSION_NAMES, rules=rules)
    if tm1.cubes.exists(CUBE_NAME):
        tm1.cubes.delete(CUBE_NAME)
    tm1.cubes.create(cube)

    # Creating the DataFrame
    df = pd.DataFrame({
        "Py Version": [VERSION_VALUE] * NUM_RECORDS,
        "Py Time": np.random.choice(ELEMENTS, size=NUM_RECORDS),
        "Py Product": np.random.choice(ELEMENTS, size=NUM_RECORDS),
        "Py Customer": np.random.choice(ELEMENTS, size=NUM_RECORDS),
        "Py Measure": np.random.choice(ELEMENTS, size=NUM_RECORDS),
        "Value": [1000] * NUM_RECORDS
    })

    before = datetime.now()
    tm1.cells.write_dataframe(cube_name=CUBE_NAME, data=df, use_blob=True)
    elapsed_time = datetime.now() - before
    print("Elapsed time with feeders: ", elapsed_time)

    if tm1.cubes.exists(CUBE_NAME):
        tm1.cubes.delete(CUBE_NAME)
    tm1.cubes.create(cube)

    before = datetime.now()
    tm1.cubes.disable_feeders(CUBE_NAME)
    tm1.cells.write_dataframe(cube_name=CUBE_NAME, data=df, use_blob=True)
    tm1.cubes.enable_feeders(CUBE_NAME)
    elapsed_time = datetime.now() - before
    print("Elapsed time without feeders: ", elapsed_time)

Output

Elapsed time with feeders:  0:07:11.574673
Elapsed time without feeders:  0:05:52.537822

@MariusWirtz
Copy link
Collaborator Author

Closed: Subject to Future Re-evaluation

@MariusWirtz MariusWirtz closed this Dec 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants