{"action":"created","comment":{"url":"https://api.github.com/repos/hyrise/hyrise/pulls/comments/214540375","pull_request_review_id":151619798,"id":214540375,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIxNDU0MDM3NQ==","diff_hunk":"@@ -0,0 +1,265 @@\n+#include \"join_graph_builder.hpp\"\n+\n+#include <algorithm>\n+#include <numeric>\n+#include <queue>\n+#include <stack>\n+\n+#include \"expression/expression_functional.hpp\"\n+#include \"expression/lqp_column_expression.hpp\"\n+#include \"logical_query_plan/join_node.hpp\"\n+#include \"logical_query_plan/predicate_node.hpp\"\n+#include \"logical_query_plan/union_node.hpp\"\n+#include \"utils/assert.hpp\"\n+\n+#include \"join_graph_edge.hpp\"\n+\n+using namespace opossum::expression_functional;  // NOLINT\n+\n+namespace opossum {\n+\n+std::optional<JoinGraph> JoinGraphBuilder::operator()(const std::shared_ptr<AbstractLQPNode>& lqp) {\n+  // No need to create a join graph consisting of just one vertex and no predicates\n+  if (_lqp_node_type_is_vertex(lqp->type)) return std::nullopt;\n+\n+  traverse(lqp);\n+\n+  /**\n+   * Turn the predicates into JoinEdges and build the JoinGraph\n+   */\n+  auto edges = join_edges_from_predicates(_vertices, _predicates);\n+  auto cross_edges = cross_edges_between_components(_vertices, edges);\n+\n+  edges.insert(edges.end(), cross_edges.begin(), cross_edges.end());\n+\n+  return JoinGraph{_vertices, edges};\n+}\n+\n+void JoinGraphBuilder::traverse(const std::shared_ptr<AbstractLQPNode>& node) {\n+  // Makes it possible to call traverse() on inputs without checking whether they exist first.\n+  if (!node) return;\n+\n+  if (_lqp_node_type_is_vertex(node->type)) {\n+    _vertices.emplace_back(node);\n+    return;\n+  }\n+\n+  switch (node->type) {\n+    case LQPNodeType::Join: {\n+      /**\n+       * Cross joins are simply being traversed past. Outer joins are hard to address during join ordering and until we\n+       * do outer joins are opaque: The outer join node is added as a vertex and traversal stops at this point.\n+       */\n+\n+      const auto join_node = std::static_pointer_cast<JoinNode>(node);\n+\n+      if (join_node->join_mode == JoinMode::Inner) {\n+        _predicates.emplace_back(join_node->join_predicate);\n+      }\n+\n+      if (join_node->join_mode == JoinMode::Inner || join_node->join_mode == JoinMode::Cross) {\n+        traverse(node->left_input());\n+        traverse(node->right_input());\n+      } else {\n+        _vertices.emplace_back(node);\n+      }\n+    } break;\n+\n+    case LQPNodeType::Predicate: {\n+      const auto predicate_node = std::static_pointer_cast<PredicateNode>(node);\n+      _predicates.emplace_back(predicate_node->predicate);\n+\n+      traverse(node->left_input());\n+    } break;\n+\n+    case LQPNodeType::Union: {\n+      /**\n+       * A UnionNode is the entry point to a disjunction, which is parsed starting from _parse_union(). Normal traversal\n+       * is commenced from the node \"below\" the Union.\n+       */\n+\n+      const auto union_node = std::static_pointer_cast<UnionNode>(node);\n+\n+      if (union_node->union_mode == UnionMode::Positions) {\n+        const auto parse_result = _parse_union(union_node);\n+\n+        traverse(parse_result.base_node);\n+        _predicates.emplace_back(parse_result.predicate);\n+      } else {\n+        _vertices.emplace_back(node);\n+      }\n+    } break;\n+\n+    default: { Fail(\"Node type cannot be used for JoinGraph, should have been detected as a vertex\"); }\n+  }\n+}\n+\n+JoinGraphBuilder::PredicateParseResult JoinGraphBuilder::_parse_predicate(\n+    const std::shared_ptr<AbstractLQPNode>& node) const {\n+  switch (node->type) {\n+    case LQPNodeType::Predicate: {\n+      const auto predicate_node = std::static_pointer_cast<PredicateNode>(node);\n+\n+      const auto left_predicate = predicate_node->predicate;\n+\n+      const auto base_node = predicate_node->left_input();\n+\n+      if (base_node->output_count() > 1) {\n+        return {base_node, left_predicate};\n+      } else {\n+        const auto parse_result_right = _parse_predicate(base_node);\n+        const auto and_predicate = and_(left_predicate, parse_result_right.predicate);\n+\n+        return {parse_result_right.base_node, and_predicate};\n+      }\n+    } break;\n+\n+    case LQPNodeType::Union:\n+      return _parse_union(std::static_pointer_cast<UnionNode>(node));\n+\n+    default:\n+      Assert(node->left_input() && !node->right_input(), \"\");\n+      return _parse_predicate(node->left_input());\n+  }\n+}\n+\n+JoinGraphBuilder::PredicateParseResult JoinGraphBuilder::_parse_union(\n+    const std::shared_ptr<UnionNode>& union_node) const {\n+  DebugAssert(union_node->left_input() && union_node->right_input(),\n+              \"UnionNode needs both inputs set in order to be parsed\");\n+\n+  const auto parse_result_left = _parse_predicate(union_node->left_input());\n+  const auto parse_result_right = _parse_predicate(union_node->right_input());\n+\n+  DebugAssert(parse_result_left.base_node == parse_result_right.base_node, \"Invalid OR not having a single base node\");\n+\n+  const auto or_predicate = or_(parse_result_left.predicate, parse_result_right.predicate);\n+\n+  return {parse_result_left.base_node, or_predicate};\n+}\n+\n+bool JoinGraphBuilder::_lqp_node_type_is_vertex(const LQPNodeType node_type) const {\n+  return node_type != LQPNodeType::Join && node_type != LQPNodeType::Union && node_type != LQPNodeType::Predicate;\n+}\n+\n+std::vector<JoinGraphEdge> JoinGraphBuilder::join_edges_from_predicates(\n+    const std::vector<std::shared_ptr<AbstractLQPNode>>& vertices,\n+    const std::vector<std::shared_ptr<AbstractExpression>>& predicates) {\n+  std::map<JoinGraphVertexSet, size_t> vertices_to_edge_idx;\n+  std::vector<JoinGraphEdge> edges;\n+\n+  for (const auto& predicate : predicates) {\n+    const auto vertex_set = _get_vertex_set_accessed_by_expression(*predicate, vertices);\n+    auto iter = vertices_to_edge_idx.find(vertex_set);\n+    if (iter == vertices_to_edge_idx.end()) {\n+      iter = vertices_to_edge_idx.emplace(vertex_set, edges.size()).first;\n+      edges.emplace_back(vertex_set);\n+    }\n+    edges[iter->second].predicates.emplace_back(predicate);\n+  }\n+\n+  return edges;\n+}\n+\n+std::vector<JoinGraphEdge> JoinGraphBuilder::cross_edges_between_components(\n+    const std::vector<std::shared_ptr<AbstractLQPNode>>& vertices, std::vector<JoinGraphEdge> edges) {\n+  /**\n+   * Create edges from the gathered JoinPlanPredicates. We can't directly create the JoinGraph from this since we want\n+   * the JoinGraph to be connected and there might be edges from CrossJoins still missing.\n+   * To make the JoinGraph connected, we identify all Components and connect them to a Chain.\n+   *\n+   * So this\n+   *   B\n+   *  / \\    D--E   F\n+   * A---C\n+   *\n+   * becomes\n+   *   B\n+   *  / \\\n+   * A---C\n+   * |\n+   * D--E\n+   * |\n+   * F\n+   *\n+   * where the edges AD and DF are being created and have no predicates. There is of course the theoretical chance that\n+   * different edges, say CD and EF would result in a better plan. We ignore this possibility for now.\n+   */\n+\n+  std::unordered_set<size_t> remaining_vertex_indices;\n+  for (auto vertex_idx = size_t{0}; vertex_idx < vertices.size(); ++vertex_idx) {\n+    remaining_vertex_indices.insert(vertex_idx);\n+  }\n+\n+  std::vector<size_t> one_vertex_per_component;\n+\n+  while (!remaining_vertex_indices.empty()) {\n+    const auto vertex_idx = *remaining_vertex_indices.begin();\n+\n+    one_vertex_per_component.emplace_back(vertex_idx);\n+\n+    std::stack<size_t> bfs_stack;\n+    bfs_stack.push(vertex_idx);\n+\n+    while (!bfs_stack.empty()) {\n+      const auto vertex_idx2 = bfs_stack.top();\n+      bfs_stack.pop();\n+\n+      remaining_vertex_indices.erase(vertex_idx2);\n+\n+      for (auto iter = edges.begin(); iter != edges.end();) {\n+        const auto& edge = *iter;\n+        if (!edge.vertex_set.test(vertex_idx2)) {\n+          ++iter;\n+          continue;\n+        }\n+\n+        auto connected_vertex_idx = edge.vertex_set.find_first();\n+        while (connected_vertex_idx != JoinGraphVertexSet::npos) {\n+          if (connected_vertex_idx != vertex_idx2) bfs_stack.push(connected_vertex_idx);\n+          connected_vertex_idx = edge.vertex_set.find_next(connected_vertex_idx);\n+        }\n+\n+        iter = edges.erase(iter);\n+      }\n+    }\n+  }\n+\n+  if (one_vertex_per_component.size() < 2) return {};\n+\n+  std::vector<JoinGraphEdge> inter_component_edges;\n+  inter_component_edges.reserve(one_vertex_per_component.size() - 1);\n+\n+  for (auto component_idx = size_t{1}; component_idx < one_vertex_per_component.size(); ++component_idx) {\n+    JoinGraphVertexSet vertex_set{vertices.size()};\n+    vertex_set.set(one_vertex_per_component[component_idx - 1]);\n+    vertex_set.set(one_vertex_per_component[component_idx]);\n+\n+    inter_component_edges.emplace_back(vertex_set);\n+  }\n+\n+  return inter_component_edges;\n+}\n+\n+JoinGraphVertexSet JoinGraphBuilder::_get_vertex_set_accessed_by_expression(\n+    const AbstractExpression& expression, const std::vector<std::shared_ptr<AbstractLQPNode>>& vertices) {\n+  auto vertex_set = JoinGraphVertexSet{vertices.size()};\n+  for (auto vertex_idx = size_t{0}; vertex_idx < vertices.size(); ++vertex_idx) {","path":"src/lib/optimizer/join_graph_builder.cpp","position":247,"original_position":247,"commit_id":"748526b7b7ac2ad107026f11f3390e19cb21e524","original_commit_id":"748526b7b7ac2ad107026f11f3390e19cb21e524","user":{"login":"timzimmermann","id":5834455,"node_id":"MDQ6VXNlcjU4MzQ0NTU=","avatar_url":"https://avatars2.githubusercontent.com/u/5834455?v=4","gravatar_id":"","url":"https://api.github.com/users/timzimmermann","html_url":"https://github.com/timzimmermann","followers_url":"https://api.github.com/users/timzimmermann/followers","following_url":"https://api.github.com/users/timzimmermann/following{/other_user}","gists_url":"https://api.github.com/users/timzimmermann/gists{/gist_id}","starred_url":"https://api.github.com/users/timzimmermann/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/timzimmermann/subscriptions","organizations_url":"https://api.github.com/users/timzimmermann/orgs","repos_url":"https://api.github.com/users/timzimmermann/repos","events_url":"https://api.github.com/users/timzimmermann/events{/privacy}","received_events_url":"https://api.github.com/users/timzimmermann/received_events","type":"User","site_admin":false},"body":"Same question as above.","created_at":"2018-09-02T13:12:26Z","updated_at":"2018-09-02T13:29:46Z","html_url":"https://github.com/hyrise/hyrise/pull/1078#discussion_r214540375","pull_request_url":"https://api.github.com/repos/hyrise/hyrise/pulls/1078","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/hyrise/hyrise/pulls/comments/214540375"},"html":{"href":"https://github.com/hyrise/hyrise/pull/1078#discussion_r214540375"},"pull_request":{"href":"https://api.github.com/repos/hyrise/hyrise/pulls/1078"}}},"pull_request":{"url":"https://api.github.com/repos/hyrise/hyrise/pulls/1078","id":211497238,"node_id":"MDExOlB1bGxSZXF1ZXN0MjExNDk3MjM4","html_url":"https://github.com/hyrise/hyrise/pull/1078","diff_url":"https://github.com/hyrise/hyrise/pull/1078.diff","patch_url":"https://github.com/hyrise/hyrise/pull/1078.patch","issue_url":"https://api.github.com/repos/hyrise/hyrise/issues/1078","number":1078,"state":"open","locked":false,"title":"JoinOrderingRule","user":{"login":"mrzzzrm","id":2679018,"node_id":"MDQ6VXNlcjI2NzkwMTg=","avatar_url":"https://avatars3.githubusercontent.com/u/2679018?v=4","gravatar_id":"","url":"https://api.github.com/users/mrzzzrm","html_url":"https://github.com/mrzzzrm","followers_url":"https://api.github.com/users/mrzzzrm/followers","following_url":"https://api.github.com/users/mrzzzrm/following{/other_user}","gists_url":"https://api.github.com/users/mrzzzrm/gists{/gist_id}","starred_url":"https://api.github.com/users/mrzzzrm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrzzzrm/subscriptions","organizations_url":"https://api.github.com/users/mrzzzrm/orgs","repos_url":"https://api.github.com/users/mrzzzrm/repos","events_url":"https://api.github.com/users/mrzzzrm/events{/privacy}","received_events_url":"https://api.github.com/users/mrzzzrm/received_events","type":"User","site_admin":false},"body":"Fixes #1081 \r\n\r\n\r\nIntroduces a JoinOrderingRule powered by DPccp (https://dl.acm.org/citation.cfm?id=1164207). \r\n\r\nThe underlying cost estimation was further simplified and is now just very straight forward logical cost model. See it as a intermediate soluation ;)\r\n@SvenLehmann, @timzimmermann and myself discussed the whole Optimizer-CostModel-CardinalityEstimation interaction this week and this PR is not meant to fully build out this architecture.\r\nThe important bit is that the cost-based rules **only** interact with the cost estimation component and do so over small interface.\r\n\r\n\r\n## Performance\r\n\r\nApparently TPC-H join ordering wasn't that bad? I seem to recall the MP had massive problems with TPC-H 5 (@adi64 @toniSta @marcelja), but in my tests it went through in less than 2s on the master with a scale factor of 1.\r\n\r\nSome queries (6, 12, 15) got slower - this is not because of join ordering as such, but because of local predicates on string columns that changed order, e.g. `l_shipdate >= '1994-01-01' AND l_shipdate < '1995-01-01'` - one order is faster than the other, but our current cardinality estimation and cost model assign the same cost to both predicates, so their resulting order is random. I could hack-fix this, but decided not to, I think Tim will fix this.\r\n\r\n```\r\nScale=1.0\r\n+-----------+-------------------+------+-------------------+------+--------+---------------------------------+\r\n| Benchmark | prev. iter/s      | runs | new iter/s        | runs | change | p-value (significant if <0.001) |\r\n+-----------+-------------------+------+-------------------+------+--------+---------------------------------+\r\n| TPC-H 1   | 0.106143422425    | 10   | 0.107446424663    | 10   | +1%    |                          0.0000 |\r\n| TPC-H 2   | 0.523863613605    | 10   | 0.529823958874    | 10   | +1%    |     (run time too short) 0.0001 |\r\n| TPC-H 3   | 0.827535748482    | 10   | 0.828190803528    | 10   | +0%    |     (run time too short) 0.9065 |\r\n| TPC-H 4   | 0.000871691911016 | 2    | 0.000912576797418 | 2    | +5%    |        (not enough runs) 0.0000 |\r\n| TPC-H 5   | 0.601907670498    | 10   | 0.668963193893    | 10   | +11%   |     (run time too short) 0.0000 |\r\n| TPC-H 6   | 1.28956949711     | 10   | 1.1786544323      | 10   | -9%    |     (run time too short) 0.0000 |\r\n| TPC-H 7   | 0.132361784577    | 10   | 0.13339394331     | 10   | +1%    |                          0.1771 |\r\n| TPC-H 8   | 0.0137062324211   | 10   | 0.740254282951    | 10   | +5301% |     (run time too short) 0.0000 |\r\n| TPC-H 9   | 0.0693450197577   | 10   | 0.414652377367    | 10   | +498%  |     (run time too short) 0.0000 |\r\n| TPC-H 10  | 0.430270910263    | 10   | 0.519147455692    | 10   | +21%   |     (run time too short) 0.0000 |\r\n| TPC-H 11  | 1.93563330173     | 10   | 4.68636655807     | 10   | +142%  |     (run time too short) 0.0000 |\r\n| TPC-H 12  | 0.776796936989    | 10   | 0.705871284008    | 10   | -9%    |     (run time too short) 0.0000 |\r\n| TPC-H 13  | 0.702049076557    | 10   | 0.807989239693    | 10   | +15%   |     (run time too short) 0.0000 |\r\n| TPC-H 14  | 1.50640630722     | 10   | 1.56736207008     | 10   | +4%    |     (run time too short) 0.0008 |\r\n| TPC-H 15  | 0.438291549683    | 10   | 0.290296584368    | 10   | -34%   |     (run time too short) 0.0000 |\r\n| TPC-H 16  | 0.366202861071    | 10   | 0.401498913765    | 10   | +10%   |     (run time too short) 0.0000 |\r\n| TPC-H 17  | 0.00817817635834  | 10   | 0.00895469170064  | 10   | +9%    |                          0.0000 |\r\n| TPC-H 18  | 0.00155706331134  | 4    | 0.00156903022435  | 4    | +1%    |        (not enough runs) 0.8629 |\r\n| TPC-H 19  | 0.0606515929103   | 10   | 0.0609992034733   | 10   | +1%    |                          0.0096 |\r\n| TPC-H 21  | 0.000621643965133 | 2    | 0.00063610059442  | 2    | +2%    |        (not enough runs) 0.4894 |\r\n| TPC-H 22  | 0.00160693004727  | 4    | 0.00162598362658  | 4    | +1%    |        (not enough runs) 0.1277 |\r\n| average   |                   |      |                   |      | +284%  |                                 |\r\n+-----------+-------------------+------+-------------------+------+--------+---------------------------------+\r\n```","created_at":"2018-08-28T17:18:28Z","updated_at":"2018-09-02T13:29:46Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b6a099eca0774c373b56c529d5389c26d9f534b7","assignee":null,"assignees":[],"requested_reviewers":[{"login":"mrks","id":575106,"node_id":"MDQ6VXNlcjU3NTEwNg==","avatar_url":"https://avatars2.githubusercontent.com/u/575106?v=4","gravatar_id":"","url":"https://api.github.com/users/mrks","html_url":"https://github.com/mrks","followers_url":"https://api.github.com/users/mrks/followers","following_url":"https://api.github.com/users/mrks/following{/other_user}","gists_url":"https://api.github.com/users/mrks/gists{/gist_id}","starred_url":"https://api.github.com/users/mrks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrks/subscriptions","organizations_url":"https://api.github.com/users/mrks/orgs","repos_url":"https://api.github.com/users/mrks/repos","events_url":"https://api.github.com/users/mrks/events{/privacy}","received_events_url":"https://api.github.com/users/mrks/received_events","type":"User","site_admin":false},{"login":"SvenLehmann","id":7254100,"node_id":"MDQ6VXNlcjcyNTQxMDA=","avatar_url":"https://avatars0.githubusercontent.com/u/7254100?v=4","gravatar_id":"","url":"https://api.github.com/users/SvenLehmann","html_url":"https://github.com/SvenLehmann","followers_url":"https://api.github.com/users/SvenLehmann/followers","following_url":"https://api.github.com/users/SvenLehmann/following{/other_user}","gists_url":"https://api.github.com/users/SvenLehmann/gists{/gist_id}","starred_url":"https://api.github.com/users/SvenLehmann/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SvenLehmann/subscriptions","organizations_url":"https://api.github.com/users/SvenLehmann/orgs","repos_url":"https://api.github.com/users/SvenLehmann/repos","events_url":"https://api.github.com/users/SvenLehmann/events{/privacy}","received_events_url":"https://api.github.com/users/SvenLehmann/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[{"id":978421305,"node_id":"MDU6TGFiZWw5Nzg0MjEzMDU=","url":"https://api.github.com/repos/hyrise/hyrise/labels/FullCI","name":"FullCI","color":"02ef0e","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/hyrise/hyrise/pulls/1078/commits","review_comments_url":"https://api.github.com/repos/hyrise/hyrise/pulls/1078/comments","review_comment_url":"https://api.github.com/repos/hyrise/hyrise/pulls/comments{/number}","comments_url":"https://api.github.com/repos/hyrise/hyrise/issues/1078/comments","statuses_url":"https://api.github.com/repos/hyrise/hyrise/statuses/748526b7b7ac2ad107026f11f3390e19cb21e524","head":{"label":"hyrise:feature/join_ordering_rule_last_attempt","ref":"feature/join_ordering_rule_last_attempt","sha":"748526b7b7ac2ad107026f11f3390e19cb21e524","user":{"login":"hyrise","id":3465095,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM0NjUwOTU=","avatar_url":"https://avatars2.githubusercontent.com/u/3465095?v=4","gravatar_id":"","url":"https://api.github.com/users/hyrise","html_url":"https://github.com/hyrise","followers_url":"https://api.github.com/users/hyrise/followers","following_url":"https://api.github.com/users/hyrise/following{/other_user}","gists_url":"https://api.github.com/users/hyrise/gists{/gist_id}","starred_url":"https://api.github.com/users/hyrise/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hyrise/subscriptions","organizations_url":"https://api.github.com/users/hyrise/orgs","repos_url":"https://api.github.com/users/hyrise/repos","events_url":"https://api.github.com/users/hyrise/events{/privacy}","received_events_url":"https://api.github.com/users/hyrise/received_events","type":"Organization","site_admin":false},"repo":{"id":87414843,"node_id":"MDEwOlJlcG9zaXRvcnk4NzQxNDg0Mw==","name":"hyrise","full_name":"hyrise/hyrise","owner":{"login":"hyrise","id":3465095,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM0NjUwOTU=","avatar_url":"https://avatars2.githubusercontent.com/u/3465095?v=4","gravatar_id":"","url":"https://api.github.com/users/hyrise","html_url":"https://github.com/hyrise","followers_url":"https://api.github.com/users/hyrise/followers","following_url":"https://api.github.com/users/hyrise/following{/other_user}","gists_url":"https://api.github.com/users/hyrise/gists{/gist_id}","starred_url":"https://api.github.com/users/hyrise/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hyrise/subscriptions","organizations_url":"https://api.github.com/users/hyrise/orgs","repos_url":"https://api.github.com/users/hyrise/repos","events_url":"https://api.github.com/users/hyrise/events{/privacy}","received_events_url":"https://api.github.com/users/hyrise/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/hyrise/hyrise","description":"Hyrise is a research in-memory database.","fork":false,"url":"https://api.github.com/repos/hyrise/hyrise","forks_url":"https://api.github.com/repos/hyrise/hyrise/forks","keys_url":"https://api.github.com/repos/hyrise/hyrise/keys{/key_id}","collaborators_url":"https://api.github.com/repos/hyrise/hyrise/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/hyrise/hyrise/teams","hooks_url":"https://api.github.com/repos/hyrise/hyrise/hooks","issue_events_url":"https://api.github.com/repos/hyrise/hyrise/issues/events{/number}","events_url":"https://api.github.com/repos/hyrise/hyrise/events","assignees_url":"https://api.github.com/repos/hyrise/hyrise/assignees{/user}","branches_url":"https://api.github.com/repos/hyrise/hyrise/branches{/branch}","tags_url":"https://api.github.com/repos/hyrise/hyrise/tags","blobs_url":"https://api.github.com/repos/hyrise/hyrise/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/hyrise/hyrise/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/hyrise/hyrise/git/refs{/sha}","trees_url":"https://api.github.com/repos/hyrise/hyrise/git/trees{/sha}","statuses_url":"https://api.github.com/repos/hyrise/hyrise/statuses/{sha}","languages_url":"https://api.github.com/repos/hyrise/hyrise/languages","stargazers_url":"https://api.github.com/repos/hyrise/hyrise/stargazers","contributors_url":"https://api.github.com/repos/hyrise/hyrise/contributors","subscribers_url":"https://api.github.com/repos/hyrise/hyrise/subscribers","subscription_url":"https://api.github.com/repos/hyrise/hyrise/subscription","commits_url":"https://api.github.com/repos/hyrise/hyrise/commits{/sha}","git_commits_url":"https://api.github.com/repos/hyrise/hyrise/git/commits{/sha}","comments_url":"https://api.github.com/repos/hyrise/hyrise/comments{/number}","issue_comment_url":"https://api.github.com/repos/hyrise/hyrise/issues/comments{/number}","contents_url":"https://api.github.com/repos/hyrise/hyrise/contents/{+path}","compare_url":"https://api.github.com/repos/hyrise/hyrise/compare/{base}...{head}","merges_url":"https://api.github.com/repos/hyrise/hyrise/merges","archive_url":"https://api.github.com/repos/hyrise/hyrise/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/hyrise/hyrise/downloads","issues_url":"https://api.github.com/repos/hyrise/hyrise/issues{/number}","pulls_url":"https://api.github.com/repos/hyrise/hyrise/pulls{/number}","milestones_url":"https://api.github.com/repos/hyrise/hyrise/milestones{/number}","notifications_url":"https://api.github.com/repos/hyrise/hyrise/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/hyrise/hyrise/labels{/name}","releases_url":"https://api.github.com/repos/hyrise/hyrise/releases{/id}","deployments_url":"https://api.github.com/repos/hyrise/hyrise/deployments","created_at":"2017-04-06T10:03:31Z","updated_at":"2018-08-31T18:18:53Z","pushed_at":"2018-09-01T15:32:09Z","git_url":"git://github.com/hyrise/hyrise.git","ssh_url":"git@github.com:hyrise/hyrise.git","clone_url":"https://github.com/hyrise/hyrise.git","svn_url":"https://github.com/hyrise/hyrise","homepage":"https://hpi.de/plattner/projects/hyrise.html","size":29211,"stargazers_count":104,"watchers_count":104,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":28,"mirror_url":null,"archived":false,"open_issues_count":63,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":28,"open_issues":63,"watchers":104,"default_branch":"master"}},"base":{"label":"hyrise:master","ref":"master","sha":"47ed4dc235c5b9f347a74efdfdcec6480a3a448d","user":{"login":"hyrise","id":3465095,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM0NjUwOTU=","avatar_url":"https://avatars2.githubusercontent.com/u/3465095?v=4","gravatar_id":"","url":"https://api.github.com/users/hyrise","html_url":"https://github.com/hyrise","followers_url":"https://api.github.com/users/hyrise/followers","following_url":"https://api.github.com/users/hyrise/following{/other_user}","gists_url":"https://api.github.com/users/hyrise/gists{/gist_id}","starred_url":"https://api.github.com/users/hyrise/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hyrise/subscriptions","organizations_url":"https://api.github.com/users/hyrise/orgs","repos_url":"https://api.github.com/users/hyrise/repos","events_url":"https://api.github.com/users/hyrise/events{/privacy}","received_events_url":"https://api.github.com/users/hyrise/received_events","type":"Organization","site_admin":false},"repo":{"id":87414843,"node_id":"MDEwOlJlcG9zaXRvcnk4NzQxNDg0Mw==","name":"hyrise","full_name":"hyrise/hyrise","owner":{"login":"hyrise","id":3465095,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM0NjUwOTU=","avatar_url":"https://avatars2.githubusercontent.com/u/3465095?v=4","gravatar_id":"","url":"https://api.github.com/users/hyrise","html_url":"https://github.com/hyrise","followers_url":"https://api.github.com/users/hyrise/followers","following_url":"https://api.github.com/users/hyrise/following{/other_user}","gists_url":"https://api.github.com/users/hyrise/gists{/gist_id}","starred_url":"https://api.github.com/users/hyrise/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hyrise/subscriptions","organizations_url":"https://api.github.com/users/hyrise/orgs","repos_url":"https://api.github.com/users/hyrise/repos","events_url":"https://api.github.com/users/hyrise/events{/privacy}","received_events_url":"https://api.github.com/users/hyrise/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/hyrise/hyrise","description":"Hyrise is a research in-memory database.","fork":false,"url":"https://api.github.com/repos/hyrise/hyrise","forks_url":"https://api.github.com/repos/hyrise/hyrise/forks","keys_url":"https://api.github.com/repos/hyrise/hyrise/keys{/key_id}","collaborators_url":"https://api.github.com/repos/hyrise/hyrise/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/hyrise/hyrise/teams","hooks_url":"https://api.github.com/repos/hyrise/hyrise/hooks","issue_events_url":"https://api.github.com/repos/hyrise/hyrise/issues/events{/number}","events_url":"https://api.github.com/repos/hyrise/hyrise/events","assignees_url":"https://api.github.com/repos/hyrise/hyrise/assignees{/user}","branches_url":"https://api.github.com/repos/hyrise/hyrise/branches{/branch}","tags_url":"https://api.github.com/repos/hyrise/hyrise/tags","blobs_url":"https://api.github.com/repos/hyrise/hyrise/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/hyrise/hyrise/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/hyrise/hyrise/git/refs{/sha}","trees_url":"https://api.github.com/repos/hyrise/hyrise/git/trees{/sha}","statuses_url":"https://api.github.com/repos/hyrise/hyrise/statuses/{sha}","languages_url":"https://api.github.com/repos/hyrise/hyrise/languages","stargazers_url":"https://api.github.com/repos/hyrise/hyrise/stargazers","contributors_url":"https://api.github.com/repos/hyrise/hyrise/contributors","subscribers_url":"https://api.github.com/repos/hyrise/hyrise/subscribers","subscription_url":"https://api.github.com/repos/hyrise/hyrise/subscription","commits_url":"https://api.github.com/repos/hyrise/hyrise/commits{/sha}","git_commits_url":"https://api.github.com/repos/hyrise/hyrise/git/commits{/sha}","comments_url":"https://api.github.com/repos/hyrise/hyrise/comments{/number}","issue_comment_url":"https://api.github.com/repos/hyrise/hyrise/issues/comments{/number}","contents_url":"https://api.github.com/repos/hyrise/hyrise/contents/{+path}","compare_url":"https://api.github.com/repos/hyrise/hyrise/compare/{base}...{head}","merges_url":"https://api.github.com/repos/hyrise/hyrise/merges","archive_url":"https://api.github.com/repos/hyrise/hyrise/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/hyrise/hyrise/downloads","issues_url":"https://api.github.com/repos/hyrise/hyrise/issues{/number}","pulls_url":"https://api.github.com/repos/hyrise/hyrise/pulls{/number}","milestones_url":"https://api.github.com/repos/hyrise/hyrise/milestones{/number}","notifications_url":"https://api.github.com/repos/hyrise/hyrise/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/hyrise/hyrise/labels{/name}","releases_url":"https://api.github.com/repos/hyrise/hyrise/releases{/id}","deployments_url":"https://api.github.com/repos/hyrise/hyrise/deployments","created_at":"2017-04-06T10:03:31Z","updated_at":"2018-08-31T18:18:53Z","pushed_at":"2018-09-01T15:32:09Z","git_url":"git://github.com/hyrise/hyrise.git","ssh_url":"git@github.com:hyrise/hyrise.git","clone_url":"https://github.com/hyrise/hyrise.git","svn_url":"https://github.com/hyrise/hyrise","homepage":"https://hpi.de/plattner/projects/hyrise.html","size":29211,"stargazers_count":104,"watchers_count":104,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":28,"mirror_url":null,"archived":false,"open_issues_count":63,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":28,"open_issues":63,"watchers":104,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/hyrise/hyrise/pulls/1078"},"html":{"href":"https://github.com/hyrise/hyrise/pull/1078"},"issue":{"href":"https://api.github.com/repos/hyrise/hyrise/issues/1078"},"comments":{"href":"https://api.github.com/repos/hyrise/hyrise/issues/1078/comments"},"review_comments":{"href":"https://api.github.com/repos/hyrise/hyrise/pulls/1078/comments"},"review_comment":{"href":"https://api.github.com/repos/hyrise/hyrise/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/hyrise/hyrise/pulls/1078/commits"},"statuses":{"href":"https://api.github.com/repos/hyrise/hyrise/statuses/748526b7b7ac2ad107026f11f3390e19cb21e524"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"timzimmermann"}}