From c196d2ce73d8351a18c19bcddd4b06d224e644fc Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Sat, 21 Jan 2023 18:27:22 +0100 Subject: Fetch in graph including results view --- bsfs/graph/result.py | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 bsfs/graph/result.py (limited to 'bsfs/graph/result.py') diff --git a/bsfs/graph/result.py b/bsfs/graph/result.py new file mode 100644 index 0000000..3009801 --- /dev/null +++ b/bsfs/graph/result.py @@ -0,0 +1,112 @@ +""" + +Part of the BlackStar filesystem (bsfs) module. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# imports +from collections import defaultdict +import typing + +# bsfs imports +from bsfs.utils import URI + +# exports +__all__: typing.Sequence[str] = ( + 'to_list_view', + 'to_dict_view', + ) + + +## code ## + +def to_list_view( + triples, + # aggregators + node: bool, + path: bool, + value: bool, # pylint: disable=unused-argument + ): + """Return an iterator over results. + + Dependent on the *node*, *path*, and *value* flags, + the respective component is omitted. + + """ + if node and path: + return iter(val for _, _, val in triples) + if node: + return iter((pred, val) for _, pred, val in triples) + if path: + return iter((subj, val) for subj, _, val in triples) + return iter((subj, pred, val) for subj, pred, val in triples) + + +def to_dict_view( + triples, + # context + one_node: bool, + one_path: bool, + unique_paths: typing.Set[typing.Union[URI, typing.Iterable[URI]]], + # aggregators + node: bool, + path: bool, + value: bool, + ) -> typing.Any: + """Return a dict of results. + + Note that triples are materialized to create this view. + + The returned structure depends on the *node*, *path*, and *value* flags. + If all flags are set to False, returns a dict(node -> dict(path -> set(values))). + Setting a flag to true omits or simplifies the respective component (if possible). + + """ + # NOTE: To create a dict, we need to materialize or make further assumptions + # (e.g., sorted in a specific order). + + data: typing.Any # disable type checks on data since it's very flexibly typed. + + # FIXME: type of data can be overwritten later on (if value) + + if node and path: + data = set() + elif node ^ path: + data = defaultdict(set) + else: + data = defaultdict(lambda: defaultdict(set)) + + for subj, pred, val in triples: + unique = pred in unique_paths + if node and path: + if value and unique and one_node and one_path: + return val + data.add(val) + elif node: + # remove node from result, group by predicate + if value and unique and one_node: + data[pred] = val + else: + data[pred].add(val) + elif path: + # remove predicate from result, group by node + if value and unique and one_path: + data[subj] = val + else: + data[subj].add(val) + else: + if value and unique: + data[subj][pred] = val + else: + data[subj][pred].add(val) + + # FIXME: Combine multiple Nodes instances into one? + + # convert defaultdict to ordinary dict + if node and path: + return data + if node ^ path: + return dict(data) + return {key: dict(val) for key, val in data.items()} + +## EOF ## -- cgit v1.2.3 From 04bb201c6162e81dbdefcb1cff9595180fa66917 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Sat, 21 Jan 2023 22:34:49 +0100 Subject: minor notes --- bsfs/graph/result.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'bsfs/graph/result.py') diff --git a/bsfs/graph/result.py b/bsfs/graph/result.py index 3009801..688929b 100644 --- a/bsfs/graph/result.py +++ b/bsfs/graph/result.py @@ -20,6 +20,11 @@ __all__: typing.Sequence[str] = ( ## code ## +# FIXME: node, path, value seem counter-intuitive: +# node.get(..., node=True) removes the node part. +# wouldn't it make more sense if node=True keeps the node part +# and node=False drops it? + def to_list_view( triples, # aggregators -- cgit v1.2.3 From 72e0bd78dc9cc1d74c3061b028040b64c0efcf9f Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Mon, 30 Jan 2023 09:52:18 +0100 Subject: flip graph fethc result flags --- bsfs/graph/result.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'bsfs/graph/result.py') diff --git a/bsfs/graph/result.py b/bsfs/graph/result.py index 688929b..00607f4 100644 --- a/bsfs/graph/result.py +++ b/bsfs/graph/result.py @@ -38,11 +38,11 @@ def to_list_view( the respective component is omitted. """ - if node and path: + if not node and not path: return iter(val for _, _, val in triples) - if node: + if not node: return iter((pred, val) for _, pred, val in triples) - if path: + if not path: return iter((subj, val) for subj, _, val in triples) return iter((subj, pred, val) for subj, pred, val in triples) @@ -57,6 +57,7 @@ def to_dict_view( node: bool, path: bool, value: bool, + default: typing.Optional[typing.Any] = None, ) -> typing.Any: """Return a dict of results. @@ -74,7 +75,7 @@ def to_dict_view( # FIXME: type of data can be overwritten later on (if value) - if node and path: + if not node and not path: data = set() elif node ^ path: data = defaultdict(set) @@ -83,24 +84,24 @@ def to_dict_view( for subj, pred, val in triples: unique = pred in unique_paths - if node and path: - if value and unique and one_node and one_path: + if not node and not path: + if not value and unique and one_node and one_path: return val data.add(val) - elif node: + elif not node: # remove node from result, group by predicate - if value and unique and one_node: + if not value and unique and one_node: data[pred] = val else: data[pred].add(val) - elif path: + elif not path: # remove predicate from result, group by node - if value and unique and one_path: + if not value and unique and one_path: data[subj] = val else: data[subj].add(val) else: - if value and unique: + if not value and unique: data[subj][pred] = val else: data[subj][pred].add(val) @@ -108,7 +109,11 @@ def to_dict_view( # FIXME: Combine multiple Nodes instances into one? # convert defaultdict to ordinary dict - if node and path: + if not node and not path and not value \ + and len(unique_paths) > 0 and one_node and one_path \ + and len(data) == 0: + return default + if not node and not path: return data if node ^ path: return dict(data) -- cgit v1.2.3 From f31a0d005785d474a37ec769c1f7f5e27aa08a57 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Wed, 8 Feb 2023 21:08:24 +0100 Subject: minor comments --- bsfs/graph/result.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'bsfs/graph/result.py') diff --git a/bsfs/graph/result.py b/bsfs/graph/result.py index 00607f4..31822f1 100644 --- a/bsfs/graph/result.py +++ b/bsfs/graph/result.py @@ -109,10 +109,12 @@ def to_dict_view( # FIXME: Combine multiple Nodes instances into one? # convert defaultdict to ordinary dict + # pylint: disable=too-many-boolean-expressions if not node and not path and not value \ and len(unique_paths) > 0 and one_node and one_path \ and len(data) == 0: return default + # pylint: enable=too-many-boolean-expressions if not node and not path: return data if node ^ path: -- cgit v1.2.3