How to Build Your Distributed Database
citusdata.com
citusdata.com
In the blog post, I used the + operator and sum() aggregate function interchangeably to be brief. Actually, those two operations are related, but have different representations in distributed relational algebra. I updated the first footnote in the post to reflect that.
For your comment, we have in fact two questions. First, is the ExtendedOp commutative with the Collect operator? Second, if it isn't, what properties do our transformations need to respect so that we can pull up the Collect? (equivalence property and associativity)
It's hard to be comprehensive about distributed relational algebra in a blog post. For example, the given logical tree doesn't have enough operator primitives to express large table joins. If you'd like, I'd be happy to get together and chat more about the details.
In other words, big data usually precedes big revenue, but most data products are priced per datum not per revenue.
So to put in indelicately, who can afford this and if they could, why would they? (after all those who could afford it, eg: bloomberg have strong reasons not to)
http://citusdata.com/citus-products/pg-shard http://citusdata.com/citus-products/cstore-fdw
At a practical level, we offer several ways to accomplish this: - We provide free, open-source extensions on standard PostgreSQL (pg_shard, cstore_fdw) - We provide a free community edition of CitusDB for added functionality (e.g. massively parallel analytic queries, distributed joins) - For enterprises, we provide a sitewide, unlimited license of CitusDB Enterprise. For smaller projects there, we provide support and a per-node license. - For start-ups, we provide a flat rate of CitusDB Enterprise irrespective of your data volume.
The right approach depends on the company and the use-case. Either way, and given the quick time-to-deployment, any of the approaches should end up as a major cost saver.
Your pricing page tells me you will charge me as much as you think I can afford, so Oracle kind of is the elephant in the room here.
If we can compute a sum as a sum of sub-sums, or a count as sum of sub-counts, this is no because addition is commutative `a+b=b+a` (i.e order of operands doesn't matter), but because addition is associative `(a+b)+c=a+(b+c)` (i.e order of operations doesn't matter).
So we can define, `sum(a,b,..,z) = a+b+..+z` whatever is the order of the operations (say `(((a+b)+c)+..+z)` or `(a+(b+(c+...+z)))` or ...). And if we have to compute the sum of two lists xs and ys, we can compute either `sum(append(xs,ys))` or `sum(sum(xs),sum(ys))`.
Likewise, if we can "pull up Collect nodes and push down Computation nodes" in some cases this is not because the involved computation commutes, but because the operation is in some sense compatible with the collection structure and its collect operation.
What we need is an associative operation used to merge the results computed on parts of the collection, so:
computation(merge_dataset(xs,ys)) = merge_results(computation(xs),computation(ys))
For summation and counting, the merge operation is addition.
For filtering the merge operation is simply the former collection collect operation.
So we have: sum(append(xs,ys)) = sum(sum(xs),sum(ys))
count(append(xs,ys)) = sum(count(xs),count(ys))
filter(append(xs,ys)) = append(filter(xs),filter(ys))
The abstract concept behind all this is monoid homomorphims (1) and, if you are looking for further readings, I wrote a post on how this concept is related to map-reduce and parallelism (2).- (1) https://en.wikipedia.org/wiki/Monoid#Monoid_homomorphisms.
- (2) http://acidalie.free.fr/unfoldvalue/blog/map-reduce-spirit.h...
"" No, we can't run averages on worker nodes, and then average those out. We need to have each worker node compute their sum(order_value) and count(order_value), and then sum(sum()) / sum(count()) on the coordinator node. ""?
Thank you.
Set 2 (5,7) = 6 average
Average of average (4,6) = 5
Average of Set 1 + Set 2 (5,4,3,5,7) = 4.8
Division is not commutative, as the article says. A simple example referring to the article's diagram of boxes:
orders_2013 has sum(price) = 10, with 3 records
orders_2014 has sum(price) = 11, with 5 records
orders_2015 has sum(price) = 31, with 7 records
Average on each node, and average them:
( (10/3)+(11/5)+(31/7) ) / 3 = 3.32063492063
Sum the price individually on each node, take the counts on each node, sum them on the master node, and divide on the master node:
(10+11+31)/(3+5+7) = (10+11+31)/15 = 3.46666666667
hence, running division on each node is not the same as finding the division across all orders. (replace my use of division with "average" and it's the same concept).
Further optimization is the fact the query engine lies on the application, so if you have N application servers you have N CPUs available for querying - as opposed to overloading a master server or having to provision read slaves.
Citus is a distributed relational database vs. Datanomic is a non-relational database.
Citus uses SQL as its query language vs. Datanomic uses Datalog.
Both support joins.
Citus is built on PostgreSQL as its data storage layer. Datanomic supports multiple storage layers.
There are more differences that can be found via Google.
Datomic is designed such that load from analytic queries is local to the quering machine (apart from storage retrieval which can be cached and replicated), thus it does not need to be ran on a shadow server or some distanced system from the live production system.
Because the data is immutable in Datomic, there is no need for worrying about locks on tables or documents for contention of future writes--since it reads the data at the time of the query starting from immutable files (joined with the database transaction 'novelty' buffer/log since the last database indexing operation).
It is also up to the querying machine to store the conclusions from such queries in whatever way they like. (If this means going to another datomic instance, or put on HDFS or GFS, by all means.)