{"action":"created","comment":{"url":"https://api.github.com/repos/apache/flink/pulls/comments/46121953","id":46121953,"diff_hunk":"@@ -0,0 +1,340 @@\n+/*\n+ * Licensed to the Apache Software Foundation (ASF) under one\n+ * or more contributor license agreements.  See the NOTICE file\n+ * distributed with this work for additional information\n+ * regarding copyright ownership.  The ASF licenses this file\n+ * to you under the Apache License, Version 2.0 (the\n+ * \"License\"); you may not use this file except in compliance\n+ * with the License.  You may obtain a copy of the License at\n+ *\n+ *     http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+package org.apache.flink.ml.nn.util\n+\n+import org.apache.flink.ml.math.{Breeze, Vector}\n+import Breeze._\n+\n+import org.apache.flink.ml.metrics.distances.{SquaredEuclideanDistanceMetric,\n+EuclideanDistanceMetric, DistanceMetric}\n+\n+import scala.collection.mutable.ListBuffer\n+import scala.collection.mutable.PriorityQueue\n+\n+/**\n+ * n-dimensional QuadTree data structure; partitions\n+ * spatial data for faster queries (e.g. KNN query)\n+ * The skeleton of the data structure was initially\n+ * based off of the 2D Quadtree found here:\n+ * http://www.cs.trinity.edu/~mlewis/CSCI1321-F11/Code/src/util/Quadtree.scala\n+ *\n+ * Many additional methods were added to the class both for\n+ * efficient KNN queries and generalizing to n-dim.\n+ *\n+ * @param minVec vector of the corner of the bounding box with smallest coordinates\n+ * @param maxVec vector of the corner of the bounding box with smallest coordinates\n+ * @param distMetric metric, must be Euclidean or squareEuclidean\n+ * @param maxPerBox threshold for number of points in each box before slitting a box\n+ */\n+class QuadTree(minVec: Vector, maxVec: Vector, distMetric: DistanceMetric, maxPerBox: Int){\n+\n+  class Node(center: Vector, width: Vector, var children: Seq[Node]) {\n+\n+    val nodeElements = new ListBuffer[Vector]\n+\n+    /** for testing purposes only; used in QuadTreeSuite.scala\n+      *\n+      * @return center and width of the box\n+      */\n+    def getCenterWidth(): (Vector, Vector) = {\n+      (center, width)\n+    }\n+\n+    def contains(queryPoint: Vector): Boolean = {\n+      overlap(queryPoint, 0.0)\n+    }\n+\n+    /** Tests if queryPoint is within a radius of the node\n+      *\n+      * @param queryPoint\n+      * @param radius\n+      * @return\n+      */\n+    def overlap(queryPoint: Vector, radius: Double): Boolean = {\n+      var count = 0\n+      for (i <- 0 to queryPoint.size - 1) {\n+        if (queryPoint(i) - radius < center(i) + width(i) / 2 &&\n+          queryPoint(i) + radius > center(i) - width(i) / 2) {\n+          count += 1\n+        }\n+      }\n+\n+      if (count == queryPoint.size) {\n+        true\n+      } else {\n+        false\n+      }\n+    }\n+\n+    /** Tests if queryPoint is near a node\n+      *\n+      * @param queryPoint\n+      * @param radius\n+      * @return\n+      */\n+    def isNear(queryPoint: Vector, radius: Double): Boolean = {\n+      if (minDist(queryPoint) < radius) {\n+        true\n+      } else {\n+        false\n+      }\n+    }\n+\n+    /**\n+     * used in error handling when computing minDist to make sure\n+     * distMetric is Euclidean or SquaredEuclidean\n+     * @param message\n+     */\n+    case class metricException(message: String) extends Exception(message)\n+\n+    /**\n+     * minDist is defined so that every point in the box\n+     * has distance to queryPoint greater than minDist\n+     * (minDist adopted from \"Nearest Neighbors Queries\" by N. Roussopoulos et al.)\n+     *\n+     * @param queryPoint\n+     * @return\n+     */\n+\n+    def minDist(queryPoint: Vector): Double = {\n+      var minDist = 0.0\n+      for (i <- 0 to queryPoint.size - 1) {\n+        if (queryPoint(i) < center(i) - width(i) / 2) {\n+          minDist += math.pow(queryPoint(i) - center(i) + width(i) / 2, 2)\n+        } else if (queryPoint(i) > center(i) + width(i) / 2) {\n+          minDist += math.pow(queryPoint(i) - center(i) - width(i) / 2, 2)\n+        }\n+      }\n+\n+      if (distMetric.isInstanceOf[SquaredEuclideanDistanceMetric]) {\n+        minDist\n+      } else if (distMetric.isInstanceOf[EuclideanDistanceMetric]) {\n+        math.sqrt(minDist)\n+      } else{\n+        throw metricException(s\" Error: metric must be Euclidean or SquaredEuclidean!\")\n+      }\n+    }\n+\n+    /**\n+     * Finds which child queryPoint lies in.  node.children is a Seq[Node], and\n+     * whichChild finds the appropriate index of that Seq.\n+     * @param queryPoint\n+     * @return\n+     */\n+    def whichChild(queryPoint: Vector): Int = {\n+      var count = 0\n+      for (i <- 0 to queryPoint.size - 1) {\n+        if (queryPoint(i) > center(i)) {\n+          count += Math.pow(2, queryPoint.size -1 - i).toInt\n+        }\n+      }\n+      count\n+    }\n+\n+    def makeChildren() {\n+      val centerClone = center.copy\n+      val cPart = partitionBox(centerClone, width)\n+      val mappedWidth = 0.5*width.asBreeze\n+      children = cPart.map(p => new Node(p, mappedWidth.fromBreeze, null))\n+\n+    }\n+\n+    /**\n+     * Recursive function that partitions a n-dim box by taking the (n-1) dimensional\n+     * plane through the center of the box keeping the n-th coordinate fixed,\n+     * then shifting it in the n-th direction up and down\n+     * and recursively applying partitionBox to the two shifted (n-1) dimensional planes.\n+     *\n+     * @param center the center of the box\n+     * @param width a vector of lengths of each dimension of the box\n+     * @return\n+     */\n+    def partitionBox(center: Vector, width: Vector): Seq[Vector] = {\n+\n+      def partitionHelper(box: Seq[Vector], dim: Int): Seq[Vector] = {\n+        if (dim >= width.size) {\n+          box\n+        } else {\n+          val newBox = box.flatMap {\n+            vector =>\n+              val (up, down) = (vector.copy, vector)\n+              up.update(dim, up(dim) - width(dim) / 4)\n+              down.update(dim, down(dim) + width(dim) / 4)\n+\n+              Seq(up,down)\n+          }\n+          partitionHelper(newBox, dim + 1)\n+        }\n+      }\n+      partitionHelper(Seq(center), 0)\n+    }\n+  }\n+\n+\n+  val root = new Node( ((minVec.asBreeze + maxVec.asBreeze)*0.5).fromBreeze,\n+    (maxVec.asBreeze - minVec.asBreeze).fromBreeze, null)\n+\n+    /**\n+     * Simple printing of tree for testing/debugging\n+     */\n+  def printTree(): Unit = {\n+    printTreeRecur(root)\n+  }\n+\n+  def printTreeRecur(node: Node){\n+    if(node.children != null) {\n+      for (c <- node.children){\n+        printTreeRecur(c)\n+      }\n+    }else{\n+      println(\"printing tree: n.nodeElements \" + node.nodeElements)\n+    }\n+  }\n+\n+  /**\n+   * Recursively adds an object to the tree\n+   * @param queryPoint\n+   */\n+  def insert(queryPoint: Vector){\n+    insertRecur(queryPoint,root)\n+  }\n+\n+  private def insertRecur(queryPoint: Vector,node: Node) {\n+    if (node.children == null) {\n+      if (node.nodeElements.length < maxPerBox ) {\n+        node.nodeElements += queryPoint\n+      } else{\n+        node.makeChildren()\n+        for (o <- node.nodeElements){\n+          insertRecur(o, node.children(node.whichChild(o)))\n+        }\n+        node.nodeElements.clear()\n+        insertRecur(queryPoint, node.children(node.whichChild(queryPoint)))\n+      }\n+    } else{\n+      insertRecur(queryPoint, node.children(node.whichChild(queryPoint)))\n+    }\n+  }\n+\n+  /**\n+   * Used to zoom in on a region near a test point for a fast KNN query.\n+   * This capability is used in the KNN query to find k \"near\" neighbors n_1,...,n_k, from\n+   * which one computes the max distance D_s to queryPoint.  D_s is then used during the\n+   * kNN query to find all points within a radius D_s of queryPoint using searchNeighbors.\n+   * To find the \"near\" neighbors, a min-heap is defined on the leaf nodes of the leaf\n+   * nodes of the minimal bounding box of the queryPoint. The priority of a leaf node\n+   * is an appropriate notion of the distance between the test point and the node,\n+   * which is defined by minDist(queryPoint),\n+   *\n+   * @param queryPoint\n+   * @return\n+   */\n+  def searchNeighborsSiblingQueue(queryPoint: Vector): ListBuffer[Vector] = {\n+    var ret = new ListBuffer[Vector]\n+    // edge case when the main box has not been partitioned at all\n+    if (root.children == null) {\n+      root.nodeElements.clone()\n+    } else {\n+      val nodeQueue = new PriorityQueue[(Double, Node)]()(Ordering.by(x => x._1))\n+      searchRecurSiblingQueue(queryPoint, root, nodeQueue)\n+\n+      var count = 0\n+      while (count < maxPerBox) {\n+        val dq = nodeQueue.dequeue()\n+        if (dq._2.nodeElements.nonEmpty) {\n+          ret ++= dq._2.nodeElements\n+          count += dq._2.nodeElements.length\n+        }\n+      }\n+      ret\n+    }\n+  }\n+\n+  /**\n+   *\n+   * @param queryPoint\n+   * @param node\n+   * @param nodeQueue defined in searchSiblingQueue, this stores nodes based on their\n+   *                  distance to node as defined by minDist\n+   */\n+  private def searchRecurSiblingQueue(queryPoint: Vector, node: Node,","path":"flink-staging/flink-ml/src/main/scala/org/apache/flink/ml/nn/QuadTree.scala","position":276,"original_position":276,"commit_id":"27114cd73af9e63e340f373f5f281cdaa1263bb6","original_commit_id":"27114cd73af9e63e340f373f5f281cdaa1263bb6","user":{"login":"tillrohrmann","id":5756858,"avatar_url":"https://avatars.githubusercontent.com/u/5756858?v=3","gravatar_id":"","url":"https://api.github.com/users/tillrohrmann","html_url":"https://github.com/tillrohrmann","followers_url":"https://api.github.com/users/tillrohrmann/followers","following_url":"https://api.github.com/users/tillrohrmann/following{/other_user}","gists_url":"https://api.github.com/users/tillrohrmann/gists{/gist_id}","starred_url":"https://api.github.com/users/tillrohrmann/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tillrohrmann/subscriptions","organizations_url":"https://api.github.com/users/tillrohrmann/orgs","repos_url":"https://api.github.com/users/tillrohrmann/repos","events_url":"https://api.github.com/users/tillrohrmann/events{/privacy}","received_events_url":"https://api.github.com/users/tillrohrmann/received_events","type":"User","site_admin":false},"body":"Parameter list formatting not consistent with rest of the code base.","created_at":"2015-11-30T09:33:10Z","updated_at":"2015-11-30T09:33:10Z","html_url":"https://github.com/apache/flink/pull/1220#discussion_r46121953","pull_request_url":"https://api.github.com/repos/apache/flink/pulls/1220","_links":{"self":{"href":"https://api.github.com/repos/apache/flink/pulls/comments/46121953"},"html":{"href":"https://github.com/apache/flink/pull/1220#discussion_r46121953"},"pull_request":{"href":"https://api.github.com/repos/apache/flink/pulls/1220"}}},"pull_request":{"url":"https://api.github.com/repos/apache/flink/pulls/1220","id":46711104,"html_url":"https://github.com/apache/flink/pull/1220","diff_url":"https://github.com/apache/flink/pull/1220.diff","patch_url":"https://github.com/apache/flink/pull/1220.patch","issue_url":"https://api.github.com/repos/apache/flink/issues/1220","number":1220,"state":"open","locked":false,"title":"[FLINK-1745] Add exact k-nearest-neighbours algorithm to machine learning library","user":{"login":"danielblazevski","id":10012612,"avatar_url":"https://avatars.githubusercontent.com/u/10012612?v=3","gravatar_id":"","url":"https://api.github.com/users/danielblazevski","html_url":"https://github.com/danielblazevski","followers_url":"https://api.github.com/users/danielblazevski/followers","following_url":"https://api.github.com/users/danielblazevski/following{/other_user}","gists_url":"https://api.github.com/users/danielblazevski/gists{/gist_id}","starred_url":"https://api.github.com/users/danielblazevski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danielblazevski/subscriptions","organizations_url":"https://api.github.com/users/danielblazevski/orgs","repos_url":"https://api.github.com/users/danielblazevski/repos","events_url":"https://api.github.com/users/danielblazevski/events{/privacy}","received_events_url":"https://api.github.com/users/danielblazevski/received_events","type":"User","site_admin":false},"body":"I added a quadtree data structure for the knn algorithm.  @chiwanpark made originally made a pull request for a kNN algorithm, and we coordinated so that I incorporate a tree structure. The quadtree scales very well with the number of training + test points, but scales poorly with the dimension (even the R-tree scales poorly with the dimension). I added a flag that is automatically determines whether or not to use the quadtree. My implementation needed to use the Euclidean or SquaredEuclidean distance since I needed a specific notion of the distance between a test point and a box in the quadtree. I added another test KNNQuadTreeSuite in addition to Chiwan Park's KNNITSuite, since C. Park's parameters will automatically choose the brute-force non-quadtree method.\r\n\r\nFor more details on the quadtree + how I used it for the KNN query, please see another branch I created that has a README.md:\r\nhttps://github.com/danielblazevski/flink/tree/FLINK-1745-devel/flink-staging/flink-ml/src/main/scala/org/apache/flink/ml/nn\r\n","created_at":"2015-10-03T19:03:13Z","updated_at":"2015-11-30T09:33:10Z","closed_at":null,"merged_at":null,"merge_commit_sha":"dff54f74dee312a7a5dd378d4a6117c9c8bd3558","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/apache/flink/pulls/1220/commits","review_comments_url":"https://api.github.com/repos/apache/flink/pulls/1220/comments","review_comment_url":"https://api.github.com/repos/apache/flink/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/flink/issues/1220/comments","statuses_url":"https://api.github.com/repos/apache/flink/statuses/27114cd73af9e63e340f373f5f281cdaa1263bb6","head":{"label":"danielblazevski:FLINK-1745","ref":"FLINK-1745","sha":"27114cd73af9e63e340f373f5f281cdaa1263bb6","user":{"login":"danielblazevski","id":10012612,"avatar_url":"https://avatars.githubusercontent.com/u/10012612?v=3","gravatar_id":"","url":"https://api.github.com/users/danielblazevski","html_url":"https://github.com/danielblazevski","followers_url":"https://api.github.com/users/danielblazevski/followers","following_url":"https://api.github.com/users/danielblazevski/following{/other_user}","gists_url":"https://api.github.com/users/danielblazevski/gists{/gist_id}","starred_url":"https://api.github.com/users/danielblazevski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danielblazevski/subscriptions","organizations_url":"https://api.github.com/users/danielblazevski/orgs","repos_url":"https://api.github.com/users/danielblazevski/repos","events_url":"https://api.github.com/users/danielblazevski/events{/privacy}","received_events_url":"https://api.github.com/users/danielblazevski/received_events","type":"User","site_admin":false},"repo":{"id":43304224,"name":"flink","full_name":"danielblazevski/flink","owner":{"login":"danielblazevski","id":10012612,"avatar_url":"https://avatars.githubusercontent.com/u/10012612?v=3","gravatar_id":"","url":"https://api.github.com/users/danielblazevski","html_url":"https://github.com/danielblazevski","followers_url":"https://api.github.com/users/danielblazevski/followers","following_url":"https://api.github.com/users/danielblazevski/following{/other_user}","gists_url":"https://api.github.com/users/danielblazevski/gists{/gist_id}","starred_url":"https://api.github.com/users/danielblazevski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danielblazevski/subscriptions","organizations_url":"https://api.github.com/users/danielblazevski/orgs","repos_url":"https://api.github.com/users/danielblazevski/repos","events_url":"https://api.github.com/users/danielblazevski/events{/privacy}","received_events_url":"https://api.github.com/users/danielblazevski/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/danielblazevski/flink","description":"Mirror of Apache Flink","fork":true,"url":"https://api.github.com/repos/danielblazevski/flink","forks_url":"https://api.github.com/repos/danielblazevski/flink/forks","keys_url":"https://api.github.com/repos/danielblazevski/flink/keys{/key_id}","collaborators_url":"https://api.github.com/repos/danielblazevski/flink/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/danielblazevski/flink/teams","hooks_url":"https://api.github.com/repos/danielblazevski/flink/hooks","issue_events_url":"https://api.github.com/repos/danielblazevski/flink/issues/events{/number}","events_url":"https://api.github.com/repos/danielblazevski/flink/events","assignees_url":"https://api.github.com/repos/danielblazevski/flink/assignees{/user}","branches_url":"https://api.github.com/repos/danielblazevski/flink/branches{/branch}","tags_url":"https://api.github.com/repos/danielblazevski/flink/tags","blobs_url":"https://api.github.com/repos/danielblazevski/flink/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/danielblazevski/flink/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/danielblazevski/flink/git/refs{/sha}","trees_url":"https://api.github.com/repos/danielblazevski/flink/git/trees{/sha}","statuses_url":"https://api.github.com/repos/danielblazevski/flink/statuses/{sha}","languages_url":"https://api.github.com/repos/danielblazevski/flink/languages","stargazers_url":"https://api.github.com/repos/danielblazevski/flink/stargazers","contributors_url":"https://api.github.com/repos/danielblazevski/flink/contributors","subscribers_url":"https://api.github.com/repos/danielblazevski/flink/subscribers","subscription_url":"https://api.github.com/repos/danielblazevski/flink/subscription","commits_url":"https://api.github.com/repos/danielblazevski/flink/commits{/sha}","git_commits_url":"https://api.github.com/repos/danielblazevski/flink/git/commits{/sha}","comments_url":"https://api.github.com/repos/danielblazevski/flink/comments{/number}","issue_comment_url":"https://api.github.com/repos/danielblazevski/flink/issues/comments{/number}","contents_url":"https://api.github.com/repos/danielblazevski/flink/contents/{+path}","compare_url":"https://api.github.com/repos/danielblazevski/flink/compare/{base}...{head}","merges_url":"https://api.github.com/repos/danielblazevski/flink/merges","archive_url":"https://api.github.com/repos/danielblazevski/flink/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/danielblazevski/flink/downloads","issues_url":"https://api.github.com/repos/danielblazevski/flink/issues{/number}","pulls_url":"https://api.github.com/repos/danielblazevski/flink/pulls{/number}","milestones_url":"https://api.github.com/repos/danielblazevski/flink/milestones{/number}","notifications_url":"https://api.github.com/repos/danielblazevski/flink/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/danielblazevski/flink/labels{/name}","releases_url":"https://api.github.com/repos/danielblazevski/flink/releases{/id}","created_at":"2015-09-28T13:59:34Z","updated_at":"2015-10-16T07:44:19Z","pushed_at":"2015-11-29T02:28:05Z","git_url":"git://github.com/danielblazevski/flink.git","ssh_url":"git@github.com:danielblazevski/flink.git","clone_url":"https://github.com/danielblazevski/flink.git","svn_url":"https://github.com/danielblazevski/flink","homepage":null,"size":68094,"stargazers_count":1,"watchers_count":1,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"apache:master","ref":"master","sha":"6e0e67d2e0d5180d6fba492e8ab9cc8fb18fdf68","user":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"repo":{"id":20587599,"name":"flink","full_name":"apache/flink","owner":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apache/flink","description":"Mirror of Apache Flink","fork":false,"url":"https://api.github.com/repos/apache/flink","forks_url":"https://api.github.com/repos/apache/flink/forks","keys_url":"https://api.github.com/repos/apache/flink/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/flink/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/flink/teams","hooks_url":"https://api.github.com/repos/apache/flink/hooks","issue_events_url":"https://api.github.com/repos/apache/flink/issues/events{/number}","events_url":"https://api.github.com/repos/apache/flink/events","assignees_url":"https://api.github.com/repos/apache/flink/assignees{/user}","branches_url":"https://api.github.com/repos/apache/flink/branches{/branch}","tags_url":"https://api.github.com/repos/apache/flink/tags","blobs_url":"https://api.github.com/repos/apache/flink/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/flink/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/flink/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/flink/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/flink/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/flink/languages","stargazers_url":"https://api.github.com/repos/apache/flink/stargazers","contributors_url":"https://api.github.com/repos/apache/flink/contributors","subscribers_url":"https://api.github.com/repos/apache/flink/subscribers","subscription_url":"https://api.github.com/repos/apache/flink/subscription","commits_url":"https://api.github.com/repos/apache/flink/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/flink/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/flink/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/flink/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/flink/contents/{+path}","compare_url":"https://api.github.com/repos/apache/flink/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/flink/merges","archive_url":"https://api.github.com/repos/apache/flink/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/flink/downloads","issues_url":"https://api.github.com/repos/apache/flink/issues{/number}","pulls_url":"https://api.github.com/repos/apache/flink/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/flink/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/flink/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/flink/labels{/name}","releases_url":"https://api.github.com/repos/apache/flink/releases{/id}","created_at":"2014-06-07T07:00:10Z","updated_at":"2015-11-29T15:44:19Z","pushed_at":"2015-11-30T08:44:39Z","git_url":"git://github.com/apache/flink.git","ssh_url":"git@github.com:apache/flink.git","clone_url":"https://github.com/apache/flink.git","svn_url":"https://github.com/apache/flink","homepage":null,"size":85529,"stargazers_count":765,"watchers_count":765,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":514,"mirror_url":"git://git.apache.org/incubator-flink.git","open_issues_count":76,"forks":514,"open_issues":76,"watchers":765,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/flink/pulls/1220"},"html":{"href":"https://github.com/apache/flink/pull/1220"},"issue":{"href":"https://api.github.com/repos/apache/flink/issues/1220"},"comments":{"href":"https://api.github.com/repos/apache/flink/issues/1220/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/flink/pulls/1220/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/flink/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/flink/pulls/1220/commits"},"statuses":{"href":"https://api.github.com/repos/apache/flink/statuses/27114cd73af9e63e340f373f5f281cdaa1263bb6"}}}}