From 13aedb8f77ad7e76c480a8cb3f58367c611174b7 Mon Sep 17 00:00:00 2001 From: Almann Goo Date: Thu, 18 Aug 2022 19:58:14 -0700 Subject: [PATCH] rfc: graph data model This introduces the graph data type into the PartiQL type system. This does not cover query/construction/representation of graph, but is the basis for such operations. Resolves #15 --- RFCs/0025-graph-data-model.md | 176 ++++++++++++++++++++++++++ RFCs/0025-graph-data-model/graph.png | Bin 0 -> 20392 bytes RFCs/0025-graph-data-model/list.png | Bin 0 -> 3858 bytes RFCs/0025-graph-data-model/struct.png | Bin 0 -> 4054 bytes 4 files changed, 176 insertions(+) create mode 100644 RFCs/0025-graph-data-model.md create mode 100644 RFCs/0025-graph-data-model/graph.png create mode 100644 RFCs/0025-graph-data-model/list.png create mode 100644 RFCs/0025-graph-data-model/struct.png diff --git a/RFCs/0025-graph-data-model.md b/RFCs/0025-graph-data-model.md new file mode 100644 index 0000000..e93b0f5 --- /dev/null +++ b/RFCs/0025-graph-data-model.md @@ -0,0 +1,176 @@ +- Start Date: 2022-08-18 +- PartiQL Issue: [partiql/partiql-docs/#15](https://github.com/partiql/partiql-docs/issues/15) +- RFC PR: [partiql/partiql-docs/#25](https://github.com/partiql/partiql-docs/issues/25) + +# Summary +[summary]: #summary + +Introduces the graph data type for the PartiQL type system defining logical representation, but not operations on the +data type. + +# Motivation +[motivation]: #motivation + +Graph databases such as Amazon Neptune are becoming more popular for use in applications where the traditional SQL +databases and NoSQL databases are inadequate to model data with sprawling relationships. Typically, these kinds of +applications are doing path traversals over a graph in a way that that would be awkward to express in an equivalently +modeled relational database. The question is can we and should we have a representation in the PartiQL type system that +abstracts a graph, provide graph-specific query operations, and unify this with the rest of the type system as we do +with relations and structs? Much like the goal of PartiQL is to unify nested data with relational, we should be thinking +of graph data similarly. + +This proposal introduces the graph data type as a first-class type in the PartiQL type system. + +Out of scope for this document is the particular syntax around graph query itself (beyond straw proposals to demonstrate +the model and how it would operate in PartiQL) or the syntax for expressing or serializing/de-serializing graph data +directly (similar to struct or bag expressions) to/from PartiQL. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +To introduce the PartiQL graph data type, we can first consider the other _aggregate_ data types (i.e., those containing +PartiQL values) such as bag, list, and struct. We can use the struct and list data types as helpful examples. The +struct data type is a collection of members that have an *attribute name* associated with any PartiQL value. + +![Example Struct](./0025-graph-data-model/struct.png) + +In the above, the PartiQL model models the attribute names and the association to the attribute’s values are a +*property* of the struct, not a property of the value contained within the struct. This is important, and also +indicative of how we extract these associations in PartiQL: + +```sql +SELECT a, v FROM UNPIVOT my_struct AS v AT a +``` + +In this case the we use the `UNPIVOT` operator to bind the associated attribute names to their members to variables. +This query can be read informally as “find all **`a`** and **`v`** such that **`a`** and **`v`** is an attribute/value +pair in **`my_struct`**.” The list data type similarly models the association of position ordinal to member value. + +![Example List](./0025-graph-data-model/list.png) + +Which is similarly extracted as variables: + +```sql +SELECT i, v FROM my_list AS v AT i +``` + +For the graph data type, we model something very similar. A graph is a collection of *vertices* and *edges* that connect +them with associated direction. All vertices and edges have a *label* (similar to the attribute name in struct) that +must be a string or `NULL`. The value of a vertex or an edge can be any PartiQL value. The following diagram illustrates +the model: + +![Example Graph](./0025-graph-data-model/graph.png) + +In the above, we have a graph with three vertices, two labeled **`a`** and one labeled **`b`**. We have three edges, one +labeled **`x`** and two labeled **`y`**. The relationships of the edges to their respective vertices are fully contained +within the graph. All values within the graph, either an edge or vertex, can be *any* PartiQL value. This generalization +is consistent with the other container types and fits nicely in PartiQL’s data model. This also means that PartiQL +graphs *could* have vertices or edges that themselves be graphs, and likewise values can be as simple as scalar values. + +As a common example, let’s consider how we could model a *labeled property graph (LPG)* to PartiQL. For LPG, each vertex +and edge are a property bag which is a struct in PartiQL. + +Similarly, Resource Description Framework (RDF)[^1] graphs could be modeled in PartiQL by having non-literal, non-blank +vertices and edges labeled by URI strings with their values being NULL. RDF literals could be a NULL labeled node with +their value being any corresponding PartiQL value (this is a generalization of RDF as literals are only strings in RDF’s +model). RDF blank nodes can be denoted with a label that never conflicts with URI such as **`_:my_blank`** (**`_`** is +never a valid scheme for a URI). + +Even though PartiQL generalizes the graph data model, it is *not required* that a database actually exposes arbitrary +values at vertex or edge values, this is similar to PartiQL over a relational table, where attributes of a row are +restricted to scalars. + +## Data Model Integration with PartiQL Query + +The SQL/PGQ specification is currently in progress, but has published elements of their work[^2]. It is important that +PartiQL aligns to an SQL standard that arises around graph query insofar as it is practically acceptable. Let us +consider a straw example of what a PartiQL graph query could look like and mean with respect to this data model. + +```sql +SELECT the_a.name AS src, the_b.name AS dest +FROM my_graph MATCH (the_a:a) -[the_y:y]-> (the_b:b) +WHERE the_y.score > 10 +``` + +In the above example, the `MATCH` sub-clause is working similar to how `UNPIVOT` works, it is effectively saying find +all **`the_a`**, **`the_y`**, and **`the_b`** such that the graph pattern matching association holds. These names are +then bound to variables that are then usable in other clauses. In other words, the loose specification of the `MATCH` +sub-clause is that it returns a bag of variable bindings much like any other `FROM` source. Similar to the way list +ordinals and struct ordinals work, the relationship matching in the graph operators are scoped to a single graph +instance and has no implications outside of that value. Such a `MATCH` clause could be as complex as needed (having +other sub-clauses) to perform the appropriate graph query constructs. + +# Drawbacks +[drawbacks]: #drawbacks + +*TBD* + +# Rationale and Alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +Some earlier discussions in graph support for PartiQL indicated that a reference type (i.e., pointer or alias) could +“solve” adding graph data for PartiQL. While this primitive could be used to construct graphs, it would not have the +same degree of abstraction as the proposed data type and it creates and issue that an associated value that is not fully +contained within a PartiQL value. + +The abstraction problem can be illustrated by the LPG example, how might we solve this with references? Since scalars +themselves are atomic values, references would have to be contained in some container type such as a list or struct. Now +vertices **must** be a struct or a list, and now we’re defining a convention which is a substitution for strong typing. +Another problem in the abstraction is how do we model properties on the edges and multiple edges for a given label? +Again, we need to now model the edge property from the source as either a list/bag of references or a single reference +and we need to introduce an intermediate struct between the two vertex struct values with some convention. Assuming we +defined this convention, how would a different graph model work such as RDF? Another convention could be defined but now +we have the problem of how do we determine if the convention is being used or not (e.g., valid for a MATCH +sub-clause)—this is introducing the concept without typing the concept. If the answer is schema—that is the same as +saying we have some kind of notion of static type. References are being used here to serve as a potential implementation +detail that leaks into the logical model. A similar rationale could be used for the list data type. The relational model +could easily represent a list as a bag of structs containing an ordinal and value—but PartiQL has a first-class type +because it is often the case that we have operations directly on lists that are of value (e.g., accessing an element by +ordinal). + +# Prior Art +[prior-art]: #prior-art + +*TBD* + +# Unresolved Questions +[unresolved-questions]: #unresolved-questions + +## Data Model + +As defined, a graph's label *must* be a value, should it be allowed that a graph label can be `MISSING`? + +## Graph Construction + +While outside the scope of this document to define such syntax, it is important to consider how graph data types might +be serialized or constructed. A database could implement a view over a relational representation of a graph with this +data type. This pattern is seen in databases such as Oracle, where a set of tables can be treated as a graph. Likewise, +PartiQL could adopt minimal syntax extensions from something like Cypher[^3] to unify its DML with graph manipulation. +Also, similar to bag, list, and struct constructor expressions, we could introduce graph constructor expressions to +create graph values (e.g., literals in expressions). + +# Future possibilities +[future-possibilities]: #future-possibilities + +Think about what the natural extension and evolution of your proposal would +be and how it would affect the language and project as a whole in a holistic +way. Try to use this section as a tool to more fully consider all possible +interactions with the project and language in your proposal. +Also consider how this all fits into the roadmap for the project. + +This is also a good place to "dump ideas", if they are out of scope for the +RFC you are writing but otherwise related. + +If you have tried and cannot think of any future possibilities, +you may simply state that you cannot think of anything. + +Note that having something written down in the future-possibilities section +is not a reason to accept the current or a future RFC; such notes should be +in the section on motivation or rationale in this or subsequent RFCs. +The section merely provides additional information. + +[^1]: + +[^2]: + +[^3]: diff --git a/RFCs/0025-graph-data-model/graph.png b/RFCs/0025-graph-data-model/graph.png new file mode 100644 index 0000000000000000000000000000000000000000..9c8002b2ee6919cbbbeebbf9d5919bf9c8856c96 GIT binary patch literal 20392 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 literal 0 HcmV?d00001 diff --git a/RFCs/0025-graph-data-model/list.png b/RFCs/0025-graph-data-model/list.png new file mode 100644 index 0000000000000000000000000000000000000000..fcacec6fc6a2262b19dbb4c39447e9fad4139ba6 GIT binary patch literal 3858 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 B0jB@} literal 0 HcmV?d00001