{"id":76779,"date":"2019-05-01T08:00:38","date_gmt":"2019-05-01T15:00:38","guid":{"rendered":""},"modified":"2025-06-27T08:11:36","modified_gmt":"2025-06-27T15:11:36","slug":"trill-102-temporal-joins","status":"publish","type":"post","link":"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/","title":{"rendered":"Trill 102: Temporal Joins"},"content":{"rendered":"\n<p>This post is the second in a sequence intended to introduce developers to the Trill streaming query engine, its programming model, and its capabilities. We introduced in the previous <a href=\"https:\/\/cloudblogs.microsoft.com\/opensource\/2019\/03\/28\/trill-101-how-to-add-temporal-queries-to-your-applications\/\">post<\/a> the concept of <em>snapshot semantics<\/em> for temporal query processing. Here, we go deeper into the mechanics of snapshot semantics by showing its impact on one of the most basic relational operations in query processing, the Join.<\/p>\n\n\n\n<p>The join operation and how it is handled is one of the key differences between a standard relational query engine and one that operates on temporal data. What\u2019s more, how an engine accommodates a notion of time in its query language speaks volumes about how that system thinks about time management. So here, we take the time to demonstrate Trill\u2019s take on joining data.<\/p>\n\n\n\n<p>A join is, of course, a binary operation, taking two inputs and producing a single output stream. Snapshot semantics tells us that we want to be looking at join results at each point in time. To see this operation in action graphically, consider the following simple pair of streams with events we want to join:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/04\/Trill-2.1-1024x228.png\" alt=\"Trill diagram 1\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>With snapshot semantics, computing the join between these two sources is straightforward. A join result is present at any time when there is a matching event in each source. So, what we conceptually look for is interval overlap, where each event exists at the same time:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/04\/Trill-2.2-1024x330.png\" alt=\"Trill diagram 2\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"points-points-everywhere\">Points, points everywhere<\/h2>\n\n\n\n<p>Of course, a lot of naturally temporal data does not appear as intervals but rather as points. A sensor reading, for instance, comes into the system with a reading taken at a single time, say 10:15am. Whether that reading should be valid until the next reading, or for a certain period, or some other heuristically-driven policy is a matter for the query designer. But before any lifetime alterations are made in the query, the input data to a join would be just points, looking like this:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/04\/Trill-2.3-1024x195.png\" alt=\"Trill diagram 3\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>A common join operation over point events such as these might look something like, \u201cjoin the left and right data where the points are within 10 minutes of each other.\u201d Indeed, for engines whose query and lifetime operations are not separate, a join must be specified in that form, with an explicit temporal condition.<\/p>\n\n\n\n<p>But as with all things Trill, we need to think of data as intervals. We will need to adjust the lifetime of these points to bring about the join result that we want. To do so, we need to answer two questions:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Which points on the left and right should match each other?<\/li>\n\n\n\n<li>What lifetime do we expect the result to have?<\/li>\n<\/ul>\n\n\n\n<p>To answer both simultaneously, we need to reformulate the initial question. \u201cJoin left and right data within 10 minutes\u201d alone only addresses the first point.<\/p>\n\n\n\n<p>Here is one way to reformulate the question: \u201cReturn all data from the left, matched with any data from the right within 10 minutes.\u201d The asymmetric nature of this new question gives us the lifetime information that we want \u2013 we\u2019re using the data on the left as a pivot, so we want to preserve whatever the lifetime information was in the left data.<\/p>\n\n\n\n<p>To effect the correct result for this question, we need to take the data on the right and adjust its lifetime to include the plus\/minus 10 minute time window. Because we use the left data as the pivot, we leave it alone. The resulting lifespans, along with the join query result, look like this:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/04\/Trill-2.4-1024x307.png\" alt=\"Trill diagram 4\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Conversely, we could have used the data on the right of the join as the pivot. Had we instead asked, \u201cReturn all data from the right, matched with any data from the left within 10 minutes,\u201d we alter the left input data lifespans with the 10 minute time window, getting a different diagram and query result:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/04\/Trill-2.5-1024x329.png\" alt=\"Trill diagram 5\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Both join results yield the same two data points, just at different times: one with the original times of the events from the left stream, and one from the events on the right.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"time-is-of-the-essence\">Time is of the essence<\/h2>\n\n\n\n<p>There is yet another way to formulate the question, which also happens to be the default way that temporal joins over points works in many systems: \u201cReturn data from the left and right that occur within 10 minutes of each other, as quickly as possible with whatever timestamp is convenient.\u201d That sentence is a mouthful, but its intent is clear: What\u2019s important is finding whatever data matches, and the resulting lifetimes are irrelevant so long as latency is minimal.<\/p>\n\n\n\n<p>The problem with latency in the left-pivot and right-pivot cases is that the width of the lifetime extensions may impact latency. Intuitively, the wider one expands a lifetime in a join input, the more latency as the system must wait longer for potential matches. There is a way to change the event lifetimes to get the same results but with smaller overall time windows, as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/04\/Trill-2.6-1024x336.png\" alt=\"Trill diagram 6\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>In this diagram, instead of extending one side\u2019s events by 10 minutes in both directions, we extend events on both sides by 10 minutes in one direction. We get the same two results thanks to the overlap in time intervals. The lifespans of the result events are\u2026 complicated, roughly belonging to whichever of the joined events happened second.<\/p>\n\n\n\n<p>What\u2019s the takeaway here? One big advantage of having the join operation use snapshot semantics is that there is a wide variety of possibilities for returning results that allow the query author control over the result. The temporal join offered by other streaming systems is possible, but so are other variants that may be more semantically correct if desired.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"like-siblings-on-a-car-trip-i-m-only-going-if-you-re-not\">Like siblings on a car trip: I\u2019m only going if you\u2019re not<\/h2>\n\n\n\n<p>With this understanding of join in hand, we can take our newfound knowledge and apply it to other binary operations as well. What if we wanted to take an anti-semijoin of our two data streams instead?<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/04\/Trill-2.7-1024x323.png\" alt=\"Trill diagram 7\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>The result stream will consist of intervals that represent when a left event exists, but a right event does not. What we end up with is interval subtraction instead of intersection. One could then ask the same question as before with Join: If we have point streams instead of intervals, what are my possibilities for computing an anti-semijoin in Trill?<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/04\/Trill-2.8-1024x185.png\" alt=\"Trill diagram 8\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>How one defines anti-semijoin here depends entirely on desired semantics and latency requirements. One possibility, motivated by the first point-join arrangement before, would use the left stream as a pivot and adjust the lifetimes of right-stream data:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/04\/Trill-2.9-1024x314.png\" alt=\"Trill diagram 9\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Is this \u201ccorrect\u201d? The answer is in the eye of the beholder. The good news, though, is that irrespective of your requirements for correctness and for latency, there is a way to map those requirements to lifespan intervals in Trill.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"are-we-there-yet\">Are we there yet?<\/h2>\n\n\n\n<p>Between this post and the previous one, we have covered a fair amount of Trill\u2019s basic query surface. We still need to show a little more about how aggregations work, as well as Trill\u2019s support for automata and regular expressions. But before that, one big piece remaining is describing how to get data into and out of Trill, so our next tutorial post will cover ingress policies and temporal order. Until then, as always, please feel free to look at our <a href=\"https:\/\/github.com\/Microsoft\/Trill\">code<\/a>, skim through our <a href=\"https:\/\/github.com\/Microsoft\/TrillSamples\">usage samples<\/a>, and <a href=\"mailto:asktrill@microsoft.com\">let us know<\/a> if there\u2019s something you\u2019d like to see more detail on.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post is the second in a sequence intended to introduce developers to the Trill streaming query engine, its programming model, and its capabilities. We introduced in the previous post the concept of snapshot semantics for temporal query processing.<\/p>\n","protected":false},"author":5562,"featured_media":95464,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"msxcm_post_with_no_image":false,"ep_exclude_from_search":false,"_classifai_error":"","_classifai_text_to_speech_error":"","footnotes":""},"post_tag":[2272],"content-type":[340],"topic":[2238,2239],"programming-languages":[],"coauthors":[424],"class_list":["post-76779","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-microsoft","content-type-tutorials-and-demos","topic-ai-machine-learning","topic-analytics","review-flag-1593580428-734","review-flag-alway-1593580310-39","review-flag-free-1593619513-693","review-flag-new-1593580248-669"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.2 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Trill 102: Temporal Joins | Microsoft Open Source Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Trill 102: Temporal Joins | Microsoft Open Source Blog\" \/>\n<meta property=\"og:description\" content=\"This post is the second in a sequence intended to introduce developers to the Trill streaming query engine, its programming model, and its capabilities. We introduced in the previous post the concept of snapshot semantics for temporal query processing.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/\" \/>\n<meta property=\"og:site_name\" content=\"Microsoft Open Source Blog\" \/>\n<meta property=\"article:published_time\" content=\"2019-05-01T15:00:38+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-27T15:11:36+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/CLO19_Ubisoft_Azure_030.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1170\" \/>\n\t<meta property=\"og:image:height\" content=\"640\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"James Terwilliger\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@OpenAtMicrosoft\" \/>\n<meta name=\"twitter:site\" content=\"@OpenAtMicrosoft\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"James Terwilliger\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 min read\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/\"},\"author\":[{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/author\/james-terwilliger\/\",\"@type\":\"Person\",\"@name\":\"James Terwilliger\"}],\"headline\":\"Trill 102: Temporal Joins\",\"datePublished\":\"2019-05-01T15:00:38+00:00\",\"dateModified\":\"2025-06-27T15:11:36+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/\"},\"wordCount\":1231,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/CLO19_Ubisoft_Azure_030.webp\",\"keywords\":[\"Microsoft\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/\",\"url\":\"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/\",\"name\":\"Trill 102: Temporal Joins | Microsoft Open Source Blog\",\"isPartOf\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/CLO19_Ubisoft_Azure_030.webp\",\"datePublished\":\"2019-05-01T15:00:38+00:00\",\"dateModified\":\"2025-06-27T15:11:36+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/#primaryimage\",\"url\":\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/CLO19_Ubisoft_Azure_030.webp\",\"contentUrl\":\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/CLO19_Ubisoft_Azure_030.webp\",\"width\":1170,\"height\":640,\"caption\":\"A woman smiles at coworker in an office.\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/opensource.microsoft.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Trill 102: Temporal Joins\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/#website\",\"url\":\"https:\/\/opensource.microsoft.com\/blog\/\",\"name\":\"Microsoft Open Source Blog\",\"description\":\"Open dialogue about openness at Microsoft \u2013 open source, standards, interoperability\",\"publisher\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/opensource.microsoft.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/#organization\",\"name\":\"Microsoft Open Source Blog\",\"url\":\"https:\/\/opensource.microsoft.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/08\/Microsoft-Logo.png\",\"contentUrl\":\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/08\/Microsoft-Logo.png\",\"width\":259,\"height\":194,\"caption\":\"Microsoft Open Source Blog\"},\"image\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/OpenAtMicrosoft\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Trill 102: Temporal Joins | Microsoft Open Source Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/","og_locale":"en_US","og_type":"article","og_title":"Trill 102: Temporal Joins | Microsoft Open Source Blog","og_description":"This post is the second in a sequence intended to introduce developers to the Trill streaming query engine, its programming model, and its capabilities. We introduced in the previous post the concept of snapshot semantics for temporal query processing.","og_url":"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/","og_site_name":"Microsoft Open Source Blog","article_published_time":"2019-05-01T15:00:38+00:00","article_modified_time":"2025-06-27T15:11:36+00:00","og_image":[{"width":1170,"height":640,"url":"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/CLO19_Ubisoft_Azure_030.png","type":"image\/png"}],"author":"James Terwilliger","twitter_card":"summary_large_image","twitter_creator":"@OpenAtMicrosoft","twitter_site":"@OpenAtMicrosoft","twitter_misc":{"Written by":"James Terwilliger","Est. reading time":"5 min read"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/#article","isPartOf":{"@id":"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/"},"author":[{"@id":"https:\/\/opensource.microsoft.com\/blog\/author\/james-terwilliger\/","@type":"Person","@name":"James Terwilliger"}],"headline":"Trill 102: Temporal Joins","datePublished":"2019-05-01T15:00:38+00:00","dateModified":"2025-06-27T15:11:36+00:00","mainEntityOfPage":{"@id":"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/"},"wordCount":1231,"commentCount":0,"publisher":{"@id":"https:\/\/opensource.microsoft.com\/blog\/#organization"},"image":{"@id":"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/#primaryimage"},"thumbnailUrl":"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/CLO19_Ubisoft_Azure_030.webp","keywords":["Microsoft"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/","url":"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/","name":"Trill 102: Temporal Joins | Microsoft Open Source Blog","isPartOf":{"@id":"https:\/\/opensource.microsoft.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/#primaryimage"},"image":{"@id":"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/#primaryimage"},"thumbnailUrl":"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/CLO19_Ubisoft_Azure_030.webp","datePublished":"2019-05-01T15:00:38+00:00","dateModified":"2025-06-27T15:11:36+00:00","breadcrumb":{"@id":"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/#primaryimage","url":"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/CLO19_Ubisoft_Azure_030.webp","contentUrl":"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/CLO19_Ubisoft_Azure_030.webp","width":1170,"height":640,"caption":"A woman smiles at coworker in an office."},{"@type":"BreadcrumbList","@id":"https:\/\/opensource.microsoft.com\/blog\/2019\/05\/01\/trill-102-temporal-joins\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/opensource.microsoft.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Trill 102: Temporal Joins"}]},{"@type":"WebSite","@id":"https:\/\/opensource.microsoft.com\/blog\/#website","url":"https:\/\/opensource.microsoft.com\/blog\/","name":"Microsoft Open Source Blog","description":"Open dialogue about openness at Microsoft \u2013 open source, standards, interoperability","publisher":{"@id":"https:\/\/opensource.microsoft.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/opensource.microsoft.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/opensource.microsoft.com\/blog\/#organization","name":"Microsoft Open Source Blog","url":"https:\/\/opensource.microsoft.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/opensource.microsoft.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/08\/Microsoft-Logo.png","contentUrl":"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/08\/Microsoft-Logo.png","width":259,"height":194,"caption":"Microsoft Open Source Blog"},"image":{"@id":"https:\/\/opensource.microsoft.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/OpenAtMicrosoft"]}]}},"msxcm_display_generated_audio":false,"msxcm_animated_featured_image":null,"distributor_meta":false,"distributor_terms":false,"distributor_media":false,"distributor_original_site_name":"Microsoft Open Source Blog","distributor_original_site_url":"https:\/\/opensource.microsoft.com\/blog","push-errors":false,"_links":{"self":[{"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/posts\/76779","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/users\/5562"}],"replies":[{"embeddable":true,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/comments?post=76779"}],"version-history":[{"count":1,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/posts\/76779\/revisions"}],"predecessor-version":[{"id":97767,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/posts\/76779\/revisions\/97767"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/media\/95464"}],"wp:attachment":[{"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/media?parent=76779"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/post_tag?post=76779"},{"taxonomy":"content-type","embeddable":true,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/content-type?post=76779"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/topic?post=76779"},{"taxonomy":"programming-languages","embeddable":true,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/programming-languages?post=76779"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/coauthors?post=76779"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}