<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Amir Kafri on Medium]]></title>
        <description><![CDATA[Stories by Amir Kafri on Medium]]></description>
        <link>https://medium.com/@amirkafri?source=rss-4e35dc254d6d------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*D1fj5PtB62OOLAbTsukPdw.jpeg</url>
            <title>Stories by Amir Kafri on Medium</title>
            <link>https://medium.com/@amirkafri?source=rss-4e35dc254d6d------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 11:06:55 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@amirkafri/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Taming the Beast]]></title>
            <link>https://medium.com/datorama-engineering/taming-the-beast-5208e40523e3?source=rss-4e35dc254d6d------2</link>
            <guid isPermaLink="false">https://medium.com/p/5208e40523e3</guid>
            <category><![CDATA[big-data]]></category>
            <category><![CDATA[apache-spark]]></category>
            <category><![CDATA[scala]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[big-data-analytics]]></category>
            <dc:creator><![CDATA[Amir Kafri]]></dc:creator>
            <pubDate>Wed, 31 Aug 2016 06:59:27 GMT</pubDate>
            <atom:updated>2016-10-13T14:27:11.066Z</atom:updated>
            <content:encoded><![CDATA[<h4>Pluto — Datorama’s Next Generation Query Engine</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8Cc0XkPQip-qplO4_bhkZw.png" /></figure><p>Imagine you’re building a marketing data warehouse for your awesome <a href="https://varianto25.com/playing-cards/code-deck">Programming Deck of Cards</a> brand. You don’t need lots of data, just some clicks and impressions metrics of your google ads, the number of mentions your brand had on Facebook posts and link all of that to your Salesforce CRM database. Kind of simple, right? Just connect to these APIs, ETL them to your database and watch them grow on your beautiful widgets.</p><p>But the reality isn’t that simple — the data is provided in inconsistent granularities, API vendors call the same entities differently, the dimensions and metrics are not exactly what your business logic implies — complexity increases quickly.</p><p>And then one day you want to add data from LinkedIn, Twitter, and your own MongoDB data, and one of your data providers notifies you of a miscalculation in the last 3 month data because of a bug.</p><p>For every change in your schema/data you enter a development cycle, which most of the times is detailed and complex, your Marketing data warehouse grows along with your development hours, and that’s never a good thing.</p><p>What we do at Datorama is take this problem and reduce it to a simple, out-of-the-box solution, so you can work on the <a href="http://shakespearelang.sourceforge.net/report/shakespeare/">Shakespearian</a> version of the cards. Of course, the fact that we have thousands of customers, each with dozens of data sources, TBs of data and millions of monthly queries — make this problem so much more interesting, challenging, and fun!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*HmJ53eXjNHfC243VtkeBCg.jpeg" /></figure><p>At the core of <a href="http://datorama.com/">Datorama</a>’s technology stack, lies Dingo. An offspring of endless hours of coding, imperative schemas (for real!), functional creativity and obscure acronyms. Those who try to debug one of its complex queries, even armed with <a href="http://i.imgur.com/eIAIx.jpg">septuple-monitor</a> and a slice of pizza, might find themselves staring at their screens while silently humming <a href="http://highscalability.com/numbers-everyone-should-know">Jeff Dean’s numbers every programmer should know</a>.</p><p>Dingo is a reliable beast, but, as any dog trainer will tell you, you cannot teach an old dog new tricks — at least not easily. Dingo isn’t flexible enough to accommodate many of the requested cool features, is very tricky to optimise and quite difficult to debug.</p><h4>So…what can Dingo do?</h4><p>In short, Dingo is a Java engine and API for running analytical queries over any source of <a href="https://en.wikipedia.org/wiki/Fact_table">factual data</a>. Upon receiving a query request from a user, it starts with collecting raw data from the relevant fact tables, then does a few iterations of joining, computing, filtering and aggregating the data until the final result can be sent to the impatient user.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/692/1*NsB6eSt7VYL0-BD3savuZw.jpeg" /></figure><p>One of the main shortcomings of this process is that there is no separation between the plan and its execution — it all occurs at once, and as such operations such as debugging or reviewing it post-process are very cumbersome, and implementing new features or inserting optimisations become difficult.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*SmgcThyoaLopnD-tHwhHxA.jpeg" /><figcaption>Pluto and friends</figcaption></figure><h4>And Pluto is born.</h4><p>Pluto is designed and architected to solve all of these problems implicitly by 1) separating the plan and its execution, 2) decoupling the logical and the physical parts of the plan, all of this along with 3) improving Dingo’s distributed data processing capabilities. The first and obvious candidate to build Pluto on top of is <a href="http://spark.apache.org/">Spark</a>. Spark has all the important building blocks— distributed computing, clear and concise API, monitoring and instrumentation tools— plus it is JV<a href="https://www.youtube.com/watch?v=WEKhJ3CYWz4">(a)M-ish</a>, so it can seamlessly integrate with Dingo’s existing code. In fact, <a href="http://spark.apache.org/sql/">Spark-SQL</a>, which is Spark’s API for handling structured data, is even a better and more exact choice since its most basic data structure, the <a href="https://jaceklaskowski.gitbooks.io/mastering-apache-spark/content/spark-sql-dataframe.html">DataFrame</a>, is essentially a data table — exactly what Dingo processes.</p><p>Like any big software evolution, the first step is to make sure that the direction you’re taking is not too far off — that it is possible to achieve the same functionality, with performance in the same dial code.</p><h3>Calculated Measurements (the lego-kit function)</h3><p>So you bought your kid (well, ok, yourself), this <a href="http://scifidesign.com/2015/05/12/lego-minifig-scale-model-of-the-millennium-falcon-has-some-insane-detail/">awesome Star Wars lego kit</a>. All the parts are there, along with the instructions, and building it perfectly will take some time and patience. However, your manager, err, kid, wants to build an amusement park from it. So you take some pieces from it, some from older lego kits, use your imagination, cook and stir, slice and dice, and <a href="http://themetapicture.com/a-dreamy-fathers-day/">BAM</a>!</p><p>One of the awesome features that give Datorama’s platform its unique lego-like flexibility (and customer support many headaches, since some users just can’t get enough of this power) is the ability to run a customised function using any of the fields, even if the other fields themselves are customised functions. This feature (among others), forces Dingo to run some of its calculations by itself, regardless of the data warehouse that stores it. This obviously complicates the processing, since some of our data is quite big, and cannot be computed by a single machine.</p><p>For example, let’s assume that <a href="https://en.wikipedia.org/wiki/Pete_Campbell">Pete</a>, our beloved user at <a href="http://madmen.wikia.com/wiki/Sterling_Cooper_Draper_Pryce">sterlingcooperdraperprice.com</a> has a Data Stream of clicks, impressions and User-Agent (i.e. Mozilla/ Chrome/ etc.), and is observing CTR (clicks/impressions) for one of his brands. Unfortunately, The Data Stream provider, “Oogle”, notified him that because of a bug in one of the browsers, (you guessed it right) <a href="http://www.urbandictionary.com/define.php?term=internet%20exploder">Internet Exploder</a>, each user click is counted twice.</p><pre><strong>Id  | UserAgent      | Clicks       | Impressions<br></strong>1   | Chrome         | 10           | 100<br>2   | I.E            | 18           | 150<br>3   | Mozilla        | 20           | 200<br>4   | Chrome         | 15           | 100<br>5   | Chrome         | 18           | 120</pre><p>Obviously, Pete would like to handle this the right way, and luckily he has Datorama in his toolbox. Pete creates a new calculated function as follows:</p><pre><strong>function &quot;game-changer&quot;:</strong><br>if UserAgent==&quot;I.E&quot;:<br>    clicks = clicks/2<br>return clicks/impressions</pre><p>Great! Pete can finally analyse his beloved CTRs, and view them on dozens of beautiful widgets!</p><p>But things aren’t that simple. Since this function must be computed in local memory, if the total size of the records exceeds it the computation will fail. So even if Pete streamed the data to one of Datorama’s heavy-duty data-warehouses, he would not be able to view all of it at once.</p><p>Lots of big data solutions’ providers encounter this problem when they wish to implement one of their secret-sauce algorithms in a Big Data architecture. However, in Datorama, the calculated function feature is one of the major differentiators we have since it essentially allows our users to write <strong>any </strong>function (besides, well, System.exit).</p><p>The fact that this feature is so central to the platform and so unique in the Big Data landscape, we decided to tackle it first.</p><p>The calculated functions feature introduces several complexities:</p><ul><li>A function can reference many fields for its computation</li><li>It can reference other calculated measurements as part of the computation, meaning that the order of computation in the rows must be determined beforehand</li><li>Some functions are very complicated</li></ul><h4><a href="https://jaceklaskowski.gitbooks.io/mastering-apache-spark/content/spark-sql-udfs.html">UDFs</a> to the rescue!</h4><p>The first thing that comes to mind when dealing with a user-defined-function is, well, using them. Spark SQL has a built-in mechanism for dealing with customised functions — UDFs (yes, User-Defined-Functions). However, the <em>user </em>in <em>UDF</em> references a Spark developer. As a first attempt, we’ve tried to generalise the <em>UDF</em> mechanism for our needs.</p><p>Although the <em>UDF</em> mechanism does have great flexibility when it comes to writing a specific function, its shortcomings are apparent when trying to compute a function over function, and it has a limit of 10 input variables (if you go with the docs) or more (if you do some hackery), but then you are limited to a single return type.</p><h4>Solution</h4><p>The solution that we found to be successful is composed of the following steps:</p><ol><li>Index the fields by their order</li><li>Serialise the calculated functions and index them by their order, so if an expression <em>e1</em> is using another expression <em>e0, e0 </em>will be computed before, thus will be found first on the compiled expressions index. Along with the compiled expressions, also keep their final types and names. The combined list of fields and calculated functions (their names and types) will be the schema for the final dataframe.</li><li>Convert the dataframe to its underlying <a href="https://jaceklaskowski.gitbooks.io/mastering-apache-spark/content/spark-rdd.html">RDD</a>, then for each row run the serialised calculated functions in their order</li><li>Create a new dataframe with the fields and calculated functions’ results according to the schema</li></ol><h4>Performance and Benchmarking</h4><p>We’ve tested few calculated functions that grasp the previous complexities:</p><ol><li>ROW-SUM: Summation of all the metrics in a row, then each additional calculated measurement will add 1 (<em>references many fields, references other calculated measurement</em>)</li><li><a href="https://en.wikipedia.org/wiki/Greatest_common_divisor">GCD</a> between two measurements (how cool is that? finding the greatest common divisor between clicks and impressions of your favourite ad?) (<em>complex function</em>)</li></ol><h4>Results</h4><ol><li>ROW-SUM: In comparison with Dingo, the Achilles heel of the Spark implementation is the row sum. Because each cell in a row is dependent on the previous cells, the computation must run sequentially (per row). Here, the optimisations of Dingo and the overhead of Spark made a significant, yet expected, difference. Dingo performed better than our Spark-based implementation quite consistently.</li><li>GCD: Here Spark performs better than Dingo as the number of rows increase. The difference between 500K rows and 1M rows is less than 10%, whereas Dingo performance is decreased linearly by the number of rows.</li></ol><h4>Conclusion</h4><p>Well, our little POC of Pluto on Spark was pretty successful. The fact that without any optimisation, the calculated functions performed as we expected (and better than that in the case of the GCD), is both a testament to Spark’s power and Pluto’s direction.</p><p>The small amount of code that it took to implement it is another great positive point to mention, this is due to Spark’s (and Scala’s) conciseness, but that should be a different post…</p><p>Check our open positions: <a href="http://datorama.com/join-us/">http://datorama.com/join-us/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5208e40523e3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/datorama-engineering/taming-the-beast-5208e40523e3">Taming the Beast</a> was originally published in <a href="https://medium.com/datorama-engineering">Datorama Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>