{"action":"created","comment":{"url":"https://api.github.com/repos/mldbai/mldb/pulls/comments/57916318","id":57916318,"diff_hunk":"@@ -0,0 +1,297 @@\n+/** frozen_column.cc                                               -*- C++ -*-\n+    Jeremy Barnes, 27 March 2016\n+    This file is part of MLDB. Copyright 2016 Datacratic. All rights reserved.\n+\n+    Implementation of code to freeze columns into a binary format.\n+*/\n+\n+#include \"frozen_column.h\"\n+#include \"tabular_dataset_column.h\"\n+#include \"mldb/arch/bitops.h\"\n+#include \"mldb/arch/bit_range_ops.h\"\n+#include \"mldb/jml/utils/compact_vector.h\"\n+#include \"mldb/jml/utils/lightweight_hash.h\"\n+#include \"mldb/http/http_exception.h\"\n+\n+using namespace std;\n+\n+namespace Datacratic {\n+namespace MLDB {\n+\n+/// Frozen column that finds each value in a lookup table\n+struct TableFrozenColumn: public FrozenColumn {\n+    TableFrozenColumn(TabularDatasetColumn & column)\n+        : table(std::move(column.indexedVals)),\n+          columnTypes(column.columnTypes)\n+    {\n+        firstEntry = column.minRowNumber;\n+        numEntries = column.maxRowNumber - column.minRowNumber + 1;\n+        hasNulls = column.sparseIndexes.size() < numEntries;\n+        indexBits = ML::highest_bit(table.size() + hasNulls) + 1;\n+        size_t numWords = (indexBits * numEntries + 31) / 32;\n+        uint32_t * data = new uint32_t[numWords];\n+        storage = std::shared_ptr<uint32_t>(data, [] (uint32_t * p) { delete[] p; });\n+\n+        if (!hasNulls) {\n+            // Contiguous rows\n+            ML::Bit_Writer<uint32_t> writer(data);\n+            for (size_t i = 0;  i < column.sparseIndexes.size();  ++i) {\n+                ExcAssertEqual(column.sparseIndexes[i].first, i);\n+                writer.write(column.sparseIndexes[i].second, indexBits);\n+            }\n+        }\n+        else {\n+            // Non-contiguous; leave gaps with a zero (null) value\n+            std::fill(data, data + numWords, 0);\n+            for (auto & r_i: column.sparseIndexes) {\n+                ML::Bit_Writer<uint32_t> writer(data);\n+                writer.skip(r_i.first * indexBits);\n+                writer.write(r_i.second + 1, indexBits);\n+            }\n+        }\n+    }\n+\n+    virtual CellValue get(uint32_t rowIndex) const\n+    {\n+        CellValue result;\n+        if (rowIndex < firstEntry)\n+            return result;\n+        rowIndex -= firstEntry;\n+        if (rowIndex >= numEntries)\n+            return result;\n+        ExcAssertLess(rowIndex, numEntries);\n+        ML::Bit_Extractor<uint32_t> bits(storage.get());\n+        bits.advance(rowIndex * indexBits);\n+        int index = bits.extract<uint32_t>(indexBits);\n+        if (hasNulls) {\n+            if (index == 0)\n+                return result;\n+            else return result = table[index - 1];\n+        }\n+        else {\n+            return result = table[index];\n+        }\n+    }\n+\n+    virtual size_t size() const\n+    {\n+        return numEntries;\n+    }\n+\n+    virtual size_t memusage() const\n+    {\n+        size_t result\n+            = sizeof(*this)\n+            + (indexBits * numEntries + 31) / 8;\n+\n+        for (auto & v: table)\n+            result += v.memusage();\n+\n+        return result;\n+    }\n+\n+    virtual bool forEachDistinctValue(std::function<bool (const CellValue &, size_t)> fn) const\n+    {\n+        if (hasNulls) {\n+            if (!fn(CellValue(), columnTypes.numNulls))\n+                return false;\n+        }\n+        for (auto & v: table) {\n+            if (!fn(v, 1 /* todo: real count */))\n+                return false;\n+        }\n+\n+        return true;\n+    }\n+\n+    std::shared_ptr<const uint32_t> storage;\n+    uint32_t indexBits;\n+    uint32_t numEntries;\n+    uint64_t firstEntry;\n+    \n+    bool hasNulls;\n+    std::vector<CellValue> table;\n+    ColumnTypes columnTypes;\n+\n+    virtual ColumnTypes getColumnTypes() const\n+    {\n+        return columnTypes;\n+    }\n+\n+    static size_t bytesRequired(const TabularDatasetColumn & column)\n+    {\n+        size_t numEntries = column.maxRowNumber - column.minRowNumber + 1;\n+        size_t hasNulls = column.sparseIndexes.size() < numEntries;\n+        int indexBits = ML::highest_bit(column.indexedVals.size() + hasNulls) + 1;\n+        size_t result\n+            = sizeof(TableFrozenColumn)\n+            + (indexBits * numEntries + 31) / 8;\n+\n+        for (auto & v: column.indexedVals)\n+            result += v.memusage();\n+\n+        return result;\n+    }\n+};\n+\n+/// Sparse frozen column that finds each value in a lookup table\n+struct SparseTableFrozenColumn: public FrozenColumn {\n+    SparseTableFrozenColumn(TabularDatasetColumn & column)\n+        : table(column.indexedVals.size()), columnTypes(column.columnTypes)\n+    {\n+        firstEntry = column.minRowNumber;\n+        std::move(std::make_move_iterator(column.indexedVals.begin()),\n+                  std::make_move_iterator(column.indexedVals.end()),\n+                  table.begin());\n+        indexBits = ML::highest_bit(table.size()) + 1;\n+        rowNumBits = ML::highest_bit(column.maxRowNumber - column.minRowNumber) + 1;\n+        numEntries = column.sparseIndexes.size();\n+        size_t numWords = ((indexBits + rowNumBits) * numEntries + 31) / 32;\n+        uint32_t * data = new uint32_t[numWords];\n+        storage = std::shared_ptr<uint32_t>(data, [] (uint32_t * p) { delete[] p; });\n+            \n+        ML::Bit_Writer<uint32_t> writer(data);\n+        for (auto & i: column.sparseIndexes) {\n+            writer.write(i.first, rowNumBits);\n+            ExcAssertLess(i.second, table.size());\n+            writer.write(i.second, indexBits);\n+        }\n+\n+        size_t mem = memusage();\n+        if (mem > 30000) {\n+            using namespace std;\n+            cerr << \"table with \" << column.sparseIndexes.size()\n+                 << \" entries from \"\n+                 << column.minRowNumber << \" to \" << column.maxRowNumber\n+                 << \" and \" << table.size()\n+                 << \" uniques takes \" << mem << \" memory\" << endl;\n+\n+            for (unsigned i = 0;  i < 5 && i < table.size();  ++i) {\n+                cerr << \"  \" << table[i] << endl;\n+            }\n+        }\n+    }\n+\n+    virtual CellValue get(uint32_t rowIndex) const\n+    {\n+        CellValue result;\n+        if (rowIndex < firstEntry)\n+            return result;\n+        rowIndex -= firstEntry;\n+\n+        auto getAtIndex = [&] (uint32_t n)\n+            {\n+                ML::Bit_Extractor<uint32_t> bits(storage.get());\n+                bits.advance(n * (indexBits + rowNumBits));\n+                uint32_t rowNum = bits.extract<uint32_t>(rowNumBits);\n+                uint32_t index = bits.extract<uint32_t>(indexBits);\n+                return std::make_pair(rowNum, index);\n+            };\n+\n+        uint32_t first = 0;\n+        uint32_t last  = numEntries;\n+\n+        while (first != last) {\n+            uint32_t middle = (first + last) / 2;\n+            uint32_t rowNum, index;\n+            std::tie(rowNum, index) = getAtIndex(middle);\n+\n+            //cerr << \"first = \" << first << \" middle = \" << middle\n+            //     << \" last = \" << last << \" rowNum = \" << rowNum\n+            //     << \" looking for \" << rowIndex << endl;\n+\n+            if (rowNum == rowIndex) {\n+                ExcAssertLess(index, table.size());\n+                return result = table[index];\n+            }\n+\n+            // Break out if the element isn't there\n+            if (first + 1 == last)\n+                break;\n+\n+            if (rowNum < rowIndex) {\n+                first = middle;\n+            }\n+            else {\n+                last = middle;\n+            }\n+\n+        }\n+        \n+        return result;\n+    }\n+\n+    virtual size_t size() const\n+    {\n+        return numEntries;\n+    }\n+\n+    virtual size_t memusage() const\n+    {\n+        size_t result\n+            = sizeof(*this)\n+            + ((indexBits + rowNumBits) * numEntries + 31) / 8;\n+\n+        for (auto & v: table)\n+            result += v.memusage();\n+\n+        return result;\n+    }\n+\n+    virtual bool forEachDistinctValue(std::function<bool (const CellValue &, size_t)> fn) const\n+    {\n+        if (!fn(CellValue(), columnTypes.numNulls))\n+            return false;\n+        for (auto & v: table) {\n+            if (!fn(v, 1 /* todo: real count */))","path":"plugins/frozen_column.cc","position":246,"original_position":246,"commit_id":"f4883d70d4f22f2300c18ec9b2f1bf8032d5c6d1","original_commit_id":"f4883d70d4f22f2300c18ec9b2f1bf8032d5c6d1","user":{"login":"guyd","id":683788,"avatar_url":"https://avatars.githubusercontent.com/u/683788?v=3","gravatar_id":"","url":"https://api.github.com/users/guyd","html_url":"https://github.com/guyd","followers_url":"https://api.github.com/users/guyd/followers","following_url":"https://api.github.com/users/guyd/following{/other_user}","gists_url":"https://api.github.com/users/guyd/gists{/gist_id}","starred_url":"https://api.github.com/users/guyd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/guyd/subscriptions","organizations_url":"https://api.github.com/users/guyd/orgs","repos_url":"https://api.github.com/users/guyd/repos","events_url":"https://api.github.com/users/guyd/events{/privacy}","received_events_url":"https://api.github.com/users/guyd/received_events","type":"User","site_admin":false},"body":"Same here, should we complete that before committing?","created_at":"2016-03-30T16:08:59Z","updated_at":"2016-03-30T16:08:59Z","html_url":"https://github.com/mldbai/mldb/pull/287#discussion_r57916318","pull_request_url":"https://api.github.com/repos/mldbai/mldb/pulls/287","_links":{"self":{"href":"https://api.github.com/repos/mldbai/mldb/pulls/comments/57916318"},"html":{"href":"https://github.com/mldbai/mldb/pull/287#discussion_r57916318"},"pull_request":{"href":"https://api.github.com/repos/mldbai/mldb/pulls/287"}}},"pull_request":{"url":"https://api.github.com/repos/mldbai/mldb/pulls/287","id":64628952,"html_url":"https://github.com/mldbai/mldb/pull/287","diff_url":"https://github.com/mldbai/mldb/pull/287.diff","patch_url":"https://github.com/mldbai/mldb/pull/287.patch","issue_url":"https://api.github.com/repos/mldbai/mldb/issues/287","number":287,"state":"open","locked":false,"title":"MLDB-1507 bid request import","user":{"login":"jeremybarnes","id":112556,"avatar_url":"https://avatars.githubusercontent.com/u/112556?v=3","gravatar_id":"","url":"https://api.github.com/users/jeremybarnes","html_url":"https://github.com/jeremybarnes","followers_url":"https://api.github.com/users/jeremybarnes/followers","following_url":"https://api.github.com/users/jeremybarnes/following{/other_user}","gists_url":"https://api.github.com/users/jeremybarnes/gists{/gist_id}","starred_url":"https://api.github.com/users/jeremybarnes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jeremybarnes/subscriptions","organizations_url":"https://api.github.com/users/jeremybarnes/orgs","repos_url":"https://api.github.com/users/jeremybarnes/repos","events_url":"https://api.github.com/users/jeremybarnes/events{/privacy}","received_events_url":"https://api.github.com/users/jeremybarnes/received_events","type":"User","site_admin":false},"body":"This improves the importation of JSON-structured data like bid requests.  It has the following two main effects:\r\n\r\n1.  Bid request import throughput goes from ~15,000 per second to ~75,000 per second\r\n2.  Memory usage of bid requests is roughly 2x the gzipped file size, rather than roughly 50x the gzipped file size\r\n\r\nIt works by adding the ability for the Tabular dataset to have an open schema, and adding a Recorder interface which can be requested by something that's bulk inserting and can be specialized when the schema (or part of the schema) is known.\r\n","created_at":"2016-03-30T13:42:12Z","updated_at":"2016-03-30T16:08:59Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a62b02131112b7449c66c4cc753a161c4142b933","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/mldbai/mldb/pulls/287/commits","review_comments_url":"https://api.github.com/repos/mldbai/mldb/pulls/287/comments","review_comment_url":"https://api.github.com/repos/mldbai/mldb/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mldbai/mldb/issues/287/comments","statuses_url":"https://api.github.com/repos/mldbai/mldb/statuses/f4883d70d4f22f2300c18ec9b2f1bf8032d5c6d1","head":{"label":"mldbai:MLDB-1507-bid-request-import","ref":"MLDB-1507-bid-request-import","sha":"f4883d70d4f22f2300c18ec9b2f1bf8032d5c6d1","user":{"login":"mldbai","id":11510172,"avatar_url":"https://avatars.githubusercontent.com/u/11510172?v=3","gravatar_id":"","url":"https://api.github.com/users/mldbai","html_url":"https://github.com/mldbai","followers_url":"https://api.github.com/users/mldbai/followers","following_url":"https://api.github.com/users/mldbai/following{/other_user}","gists_url":"https://api.github.com/users/mldbai/gists{/gist_id}","starred_url":"https://api.github.com/users/mldbai/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mldbai/subscriptions","organizations_url":"https://api.github.com/users/mldbai/orgs","repos_url":"https://api.github.com/users/mldbai/repos","events_url":"https://api.github.com/users/mldbai/events{/privacy}","received_events_url":"https://api.github.com/users/mldbai/received_events","type":"Organization","site_admin":false},"repo":{"id":47634692,"name":"mldb","full_name":"mldbai/mldb","owner":{"login":"mldbai","id":11510172,"avatar_url":"https://avatars.githubusercontent.com/u/11510172?v=3","gravatar_id":"","url":"https://api.github.com/users/mldbai","html_url":"https://github.com/mldbai","followers_url":"https://api.github.com/users/mldbai/followers","following_url":"https://api.github.com/users/mldbai/following{/other_user}","gists_url":"https://api.github.com/users/mldbai/gists{/gist_id}","starred_url":"https://api.github.com/users/mldbai/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mldbai/subscriptions","organizations_url":"https://api.github.com/users/mldbai/orgs","repos_url":"https://api.github.com/users/mldbai/repos","events_url":"https://api.github.com/users/mldbai/events{/privacy}","received_events_url":"https://api.github.com/users/mldbai/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mldbai/mldb","description":"MLDB is the Machine Learning Database","fork":false,"url":"https://api.github.com/repos/mldbai/mldb","forks_url":"https://api.github.com/repos/mldbai/mldb/forks","keys_url":"https://api.github.com/repos/mldbai/mldb/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mldbai/mldb/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mldbai/mldb/teams","hooks_url":"https://api.github.com/repos/mldbai/mldb/hooks","issue_events_url":"https://api.github.com/repos/mldbai/mldb/issues/events{/number}","events_url":"https://api.github.com/repos/mldbai/mldb/events","assignees_url":"https://api.github.com/repos/mldbai/mldb/assignees{/user}","branches_url":"https://api.github.com/repos/mldbai/mldb/branches{/branch}","tags_url":"https://api.github.com/repos/mldbai/mldb/tags","blobs_url":"https://api.github.com/repos/mldbai/mldb/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mldbai/mldb/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mldbai/mldb/git/refs{/sha}","trees_url":"https://api.github.com/repos/mldbai/mldb/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mldbai/mldb/statuses/{sha}","languages_url":"https://api.github.com/repos/mldbai/mldb/languages","stargazers_url":"https://api.github.com/repos/mldbai/mldb/stargazers","contributors_url":"https://api.github.com/repos/mldbai/mldb/contributors","subscribers_url":"https://api.github.com/repos/mldbai/mldb/subscribers","subscription_url":"https://api.github.com/repos/mldbai/mldb/subscription","commits_url":"https://api.github.com/repos/mldbai/mldb/commits{/sha}","git_commits_url":"https://api.github.com/repos/mldbai/mldb/git/commits{/sha}","comments_url":"https://api.github.com/repos/mldbai/mldb/comments{/number}","issue_comment_url":"https://api.github.com/repos/mldbai/mldb/issues/comments{/number}","contents_url":"https://api.github.com/repos/mldbai/mldb/contents/{+path}","compare_url":"https://api.github.com/repos/mldbai/mldb/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mldbai/mldb/merges","archive_url":"https://api.github.com/repos/mldbai/mldb/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mldbai/mldb/downloads","issues_url":"https://api.github.com/repos/mldbai/mldb/issues{/number}","pulls_url":"https://api.github.com/repos/mldbai/mldb/pulls{/number}","milestones_url":"https://api.github.com/repos/mldbai/mldb/milestones{/number}","notifications_url":"https://api.github.com/repos/mldbai/mldb/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mldbai/mldb/labels{/name}","releases_url":"https://api.github.com/repos/mldbai/mldb/releases{/id}","deployments_url":"https://api.github.com/repos/mldbai/mldb/deployments","created_at":"2015-12-08T16:34:16Z","updated_at":"2016-03-21T11:05:10Z","pushed_at":"2016-03-30T14:55:03Z","git_url":"git://github.com/mldbai/mldb.git","ssh_url":"git@github.com:mldbai/mldb.git","clone_url":"https://github.com/mldbai/mldb.git","svn_url":"https://github.com/mldbai/mldb","homepage":"http://mldb.ai","size":15228,"stargazers_count":27,"watchers_count":27,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":9,"forks":3,"open_issues":9,"watchers":27,"default_branch":"master"}},"base":{"label":"mldbai:master","ref":"master","sha":"d339ad1bd25e1bd1f2e2cf62786b1ee1930d7ce3","user":{"login":"mldbai","id":11510172,"avatar_url":"https://avatars.githubusercontent.com/u/11510172?v=3","gravatar_id":"","url":"https://api.github.com/users/mldbai","html_url":"https://github.com/mldbai","followers_url":"https://api.github.com/users/mldbai/followers","following_url":"https://api.github.com/users/mldbai/following{/other_user}","gists_url":"https://api.github.com/users/mldbai/gists{/gist_id}","starred_url":"https://api.github.com/users/mldbai/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mldbai/subscriptions","organizations_url":"https://api.github.com/users/mldbai/orgs","repos_url":"https://api.github.com/users/mldbai/repos","events_url":"https://api.github.com/users/mldbai/events{/privacy}","received_events_url":"https://api.github.com/users/mldbai/received_events","type":"Organization","site_admin":false},"repo":{"id":47634692,"name":"mldb","full_name":"mldbai/mldb","owner":{"login":"mldbai","id":11510172,"avatar_url":"https://avatars.githubusercontent.com/u/11510172?v=3","gravatar_id":"","url":"https://api.github.com/users/mldbai","html_url":"https://github.com/mldbai","followers_url":"https://api.github.com/users/mldbai/followers","following_url":"https://api.github.com/users/mldbai/following{/other_user}","gists_url":"https://api.github.com/users/mldbai/gists{/gist_id}","starred_url":"https://api.github.com/users/mldbai/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mldbai/subscriptions","organizations_url":"https://api.github.com/users/mldbai/orgs","repos_url":"https://api.github.com/users/mldbai/repos","events_url":"https://api.github.com/users/mldbai/events{/privacy}","received_events_url":"https://api.github.com/users/mldbai/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mldbai/mldb","description":"MLDB is the Machine Learning Database","fork":false,"url":"https://api.github.com/repos/mldbai/mldb","forks_url":"https://api.github.com/repos/mldbai/mldb/forks","keys_url":"https://api.github.com/repos/mldbai/mldb/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mldbai/mldb/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mldbai/mldb/teams","hooks_url":"https://api.github.com/repos/mldbai/mldb/hooks","issue_events_url":"https://api.github.com/repos/mldbai/mldb/issues/events{/number}","events_url":"https://api.github.com/repos/mldbai/mldb/events","assignees_url":"https://api.github.com/repos/mldbai/mldb/assignees{/user}","branches_url":"https://api.github.com/repos/mldbai/mldb/branches{/branch}","tags_url":"https://api.github.com/repos/mldbai/mldb/tags","blobs_url":"https://api.github.com/repos/mldbai/mldb/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mldbai/mldb/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mldbai/mldb/git/refs{/sha}","trees_url":"https://api.github.com/repos/mldbai/mldb/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mldbai/mldb/statuses/{sha}","languages_url":"https://api.github.com/repos/mldbai/mldb/languages","stargazers_url":"https://api.github.com/repos/mldbai/mldb/stargazers","contributors_url":"https://api.github.com/repos/mldbai/mldb/contributors","subscribers_url":"https://api.github.com/repos/mldbai/mldb/subscribers","subscription_url":"https://api.github.com/repos/mldbai/mldb/subscription","commits_url":"https://api.github.com/repos/mldbai/mldb/commits{/sha}","git_commits_url":"https://api.github.com/repos/mldbai/mldb/git/commits{/sha}","comments_url":"https://api.github.com/repos/mldbai/mldb/comments{/number}","issue_comment_url":"https://api.github.com/repos/mldbai/mldb/issues/comments{/number}","contents_url":"https://api.github.com/repos/mldbai/mldb/contents/{+path}","compare_url":"https://api.github.com/repos/mldbai/mldb/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mldbai/mldb/merges","archive_url":"https://api.github.com/repos/mldbai/mldb/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mldbai/mldb/downloads","issues_url":"https://api.github.com/repos/mldbai/mldb/issues{/number}","pulls_url":"https://api.github.com/repos/mldbai/mldb/pulls{/number}","milestones_url":"https://api.github.com/repos/mldbai/mldb/milestones{/number}","notifications_url":"https://api.github.com/repos/mldbai/mldb/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mldbai/mldb/labels{/name}","releases_url":"https://api.github.com/repos/mldbai/mldb/releases{/id}","deployments_url":"https://api.github.com/repos/mldbai/mldb/deployments","created_at":"2015-12-08T16:34:16Z","updated_at":"2016-03-21T11:05:10Z","pushed_at":"2016-03-30T14:55:03Z","git_url":"git://github.com/mldbai/mldb.git","ssh_url":"git@github.com:mldbai/mldb.git","clone_url":"https://github.com/mldbai/mldb.git","svn_url":"https://github.com/mldbai/mldb","homepage":"http://mldb.ai","size":15228,"stargazers_count":27,"watchers_count":27,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":9,"forks":3,"open_issues":9,"watchers":27,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/mldbai/mldb/pulls/287"},"html":{"href":"https://github.com/mldbai/mldb/pull/287"},"issue":{"href":"https://api.github.com/repos/mldbai/mldb/issues/287"},"comments":{"href":"https://api.github.com/repos/mldbai/mldb/issues/287/comments"},"review_comments":{"href":"https://api.github.com/repos/mldbai/mldb/pulls/287/comments"},"review_comment":{"href":"https://api.github.com/repos/mldbai/mldb/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mldbai/mldb/pulls/287/commits"},"statuses":{"href":"https://api.github.com/repos/mldbai/mldb/statuses/f4883d70d4f22f2300c18ec9b2f1bf8032d5c6d1"}}}}