-
Notifications
You must be signed in to change notification settings - Fork 2
PEDS-1486: (BE) - Optimization changes to improve delivery speed #115
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
base: pcdc_dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,8 @@ | |
|
|
||
| DEFAULT_SURVIVAL_CONFIG = {"consortium": [], "excluded_variables": [], "result": {}} | ||
|
|
||
| # TODO: consider a simple cache keyed by (efs_flag, consortium, filters) to reuse guppy_data across repeated runs. | ||
|
|
||
|
|
||
| @auth.authorize_for_analysis("access") | ||
| def get_config(): | ||
|
|
@@ -24,13 +26,20 @@ def get_config(): | |
|
|
||
| @auth.authorize_for_analysis("access") | ||
| def get_result(): | ||
| # provides a Python dict built from the request JSON | ||
| args = utils.parse.parse_request_json() | ||
| config = capp.config.get("SURVIVAL", DEFAULT_SURVIVAL_CONFIG) | ||
|
|
||
| # TODO add json payload control | ||
| # TODO add check on payload nulls and stuff | ||
| # TODO add path in the config file or ENV variable | ||
| filter_sets = json.loads(json.dumps(args.get("filterSets"))) | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We were doing double work with |
||
| raw_filter_sets = args.get("filterSets") or [] | ||
| if not isinstance(raw_filter_sets, list): | ||
| raise UserError("filterSets must be a list") | ||
|
|
||
| # clean copy of list | ||
| filter_sets = list(raw_filter_sets) | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We go for a shallow vs deep copy of the list here, because i could not find that we needed inner dicts. |
||
|
|
||
| risktable_flag = config.get("result").get("risktable", False) | ||
| survival_flag = config.get("result").get("survival", False) | ||
| efs_flag = args.get('efsFlag', False) | ||
|
|
@@ -47,6 +56,7 @@ def get_result(): | |
| capp.logger.warning( | ||
| "Unable to load or find the user, check your token" | ||
| ) | ||
|
|
||
| capp.logger.info("SURVIVAL TOOL - " + json.dumps(log_obj)) | ||
|
|
||
| survival_results = {} | ||
|
|
@@ -80,6 +90,7 @@ def get_result(): | |
| AGE_AT_DISEASE_PHASE = "timings.age_at_disease_phase" | ||
| DISEASE_PHASE = "timings.disease_phase" | ||
|
|
||
|
|
||
| def fetch_data(config, filters, efs_flag): | ||
| status_str, status_var, time_var = ( | ||
| (EVENT_FREE_STATUS_STR, EVENT_FREE_STATUS_VAR, EVENT_FREE_TIME_VAR) | ||
|
|
@@ -94,23 +105,22 @@ def fetch_data(config, filters, efs_flag): | |
| guppy_data = json.load(f) | ||
| else: | ||
| guppy_data = utils.guppy.downloadDataFromGuppy( | ||
| path=capp.config['GUPPY_API'] + "/download", | ||
| type="subject", | ||
| totalCount=100000, | ||
| fields=[status_var, time_var, DISEASE_PHASE, AGE_AT_DISEASE_PHASE], | ||
| filters=( | ||
| {"AND": [ | ||
| {"IN": {"consortium": config.get('consortium')}}, | ||
| filters | ||
| ]} | ||
| if config.get('consortium') | ||
| else filters | ||
| ), | ||
| sort=[], | ||
| accessibility="accessible", | ||
| config=capp.config | ||
| ) | ||
|
|
||
| path=capp.config['GUPPY_API'] + "/download", | ||
|
paulmurdoch19 marked this conversation as resolved.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the big reason why it takes so long is because we are using the /download endpoint which attempts to transmit 40000 dictionaries with 5 key pairs in prod for the all filter. I am not sure but if its possible to get the needed data but we could try and use the /graphql endpoint.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. graphql endpoint option, I will test (thanks for endpoint Paul).
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. using the Using the
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that's going to change at scale in prod there's 40k dictionaries that have to be downloaded in the worst case and that's what's causing it to take 15 sec. When a user selects a filter-set to use it checks to see if the filter-set is in scope using this endpoint /analysis/tools/stats/consortiums which uses the guppy download endpoint. Since we're only finding the consortium counts we can have the /analysis/tools/stats/consortiums use the graphql endpoint instead similar to how the summary page displays the counts.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the display counts is actually reading from the same download endpoint and cache the result since they are static between data release.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
paulmurdoch19 marked this conversation as resolved.
|
||
| type="subject", | ||
| totalCount=100000, | ||
| fields=[status_var, time_var, DISEASE_PHASE, AGE_AT_DISEASE_PHASE], | ||
| filters=( | ||
| {"AND": [ | ||
| {"IN": {"consortium": config.get('consortium')}}, | ||
| filters | ||
| ]} | ||
| if config.get('consortium') | ||
| else filters | ||
| ), | ||
| sort=[], | ||
| accessibility="accessible", | ||
| config=capp.config | ||
| ) | ||
|
|
||
| node, age_at_disease_phase = AGE_AT_DISEASE_PHASE.split('.') | ||
| node, disease_phase = DISEASE_PHASE.split('.') | ||
|
|
@@ -160,7 +170,6 @@ def fetch_data(config, filters, efs_flag): | |
| raise NotFoundError("The cohort selected has no {} and/or no {}. The curve can't be built without these necessary data points.".format( | ||
| EVENT_FREE_STATUS_VAR if efs_flag else OVERALL_STATUS_VAR, EVENT_FREE_TIME_VAR if efs_flag else OVERALL_TIME_VAR)) | ||
|
|
||
|
|
||
| return ( | ||
| pd.DataFrame.from_records(guppy_data) | ||
| .assign( | ||
|
|
@@ -208,7 +217,7 @@ def get_survival_result(data, risktable_flag, survival_flag): | |
| # data_kmf['time'] = data_kmf['time'].astype(float) | ||
|
|
||
| # print(result) | ||
| data_kmf.info() | ||
| # data_kmf.info() | ||
|
paulmurdoch19 marked this conversation as resolved.
|
||
| # print(data_kmf) | ||
|
|
||
| if result["count"]["fitted"] == 0: | ||
|
|
@@ -292,9 +301,3 @@ def check_allowed_filter(config, filter_set): | |
| if value in user_filter_str: | ||
| raise UserError("One or more filters selected contains a variable that is not allowed. List of variable that are not allowed: {}".format(excluded_variables)) | ||
| return True | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that we can add caching