{"action":"created","comment":{"url":"https://api.github.com/repos/elastic/elasticsearch/pulls/comments/38519225","id":38519225,"diff_hunk":"@@ -0,0 +1,374 @@\n+/*\n+ * Licensed to Elasticsearch under one or more contributor\n+ * license agreements. See the NOTICE file distributed with\n+ * this work for additional information regarding copyright\n+ * ownership. Elasticsearch licenses this file to you under\n+ * the Apache License, Version 2.0 (the \"License\"); you may\n+ * not use this file except in compliance with the License.\n+ * 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,\n+ * software distributed under the License is distributed on an\n+ * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n+ * KIND, either express or implied.  See the License for the\n+ * specific language governing permissions and limitations\n+ * under the License.\n+ */\n+\n+package org.elasticsearch.index.query;\n+\n+import com.spatial4j.core.io.GeohashUtils;\n+import com.spatial4j.core.shape.Rectangle;\n+\n+import org.apache.lucene.search.BooleanClause;\n+import org.apache.lucene.search.BooleanQuery;\n+import org.apache.lucene.search.ConstantScoreQuery;\n+import org.apache.lucene.search.MatchNoDocsQuery;\n+import org.apache.lucene.search.NumericRangeQuery;\n+import org.apache.lucene.search.Query;\n+import org.elasticsearch.common.geo.GeoPoint;\n+import org.elasticsearch.common.geo.GeoUtils;\n+import org.elasticsearch.common.settings.Settings;\n+import org.elasticsearch.index.Index;\n+import org.elasticsearch.index.fielddata.IndexFieldData;\n+import org.elasticsearch.index.fielddata.IndexFieldDataService;\n+import org.elasticsearch.index.fielddata.plain.GeoPointDoubleArrayIndexFieldData;\n+import org.elasticsearch.index.mapper.MappedFieldType;\n+import org.elasticsearch.index.query.GeoBoundingBoxQueryBuilder.Type;\n+import org.elasticsearch.index.search.geo.InMemoryGeoBoundingBoxQuery;\n+import org.elasticsearch.test.geo.RandomShapeGenerator;\n+import org.junit.Before;\n+import org.junit.Test;\n+\n+import java.io.IOException;\n+\n+public class GeoBoundingBoxQueryBuilderTest extends BaseQueryTestCase<GeoBoundingBoxQueryBuilder> {\n+    /** Randomly generate either NaN or one of the two infinity values. */\n+    private static Double[] invalidDoubles = {Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY};\n+\n+    /** Mocks IndexFieldDataService to enable checking the \"MEMORY\"*/\n+    private class MockIndexFieldDataService extends IndexFieldDataService {\n+\n+        public MockIndexFieldDataService(Index index, Settings settings) {\n+            super(index, settings, null, null);\n+        }\n+\n+        public IndexFieldData getForField(MappedFieldType ignored) {\n+            MappedFieldType.Names names = new MappedFieldType.Names(index.getName());\n+            IndexFieldData fieldData = new GeoPointDoubleArrayIndexFieldData(index, indexSettings(), names, null, null, null);\n+            return fieldData;\n+        }\n+    }\n+\n+    @Before\n+    public void setup() {\n+        IndexFieldDataService fieldDataService = new MockIndexFieldDataService(getIndex(), getIndexSettings());\n+        super.queryParserService().setFieldDataService(fieldDataService);\n+    }\n+\n+    @Override\n+    protected GeoBoundingBoxQueryBuilder doCreateTestQueryBuilder() {\n+        GeoBoundingBoxQueryBuilder builder = new GeoBoundingBoxQueryBuilder(\"mapped_geo\");\n+        Rectangle box = RandomShapeGenerator.xRandomRectangle(getRandom(), RandomShapeGenerator.xRandomPoint(getRandom()));\n+\n+        if (frequently()) {\n+            // check the top-left/bottom-right combination of setters\n+            int path = randomIntBetween(0, 2);\n+            switch (path) {\n+            case 0:\n+                builder.topLeft(new GeoPoint(box.getMaxY(), box.getMinX()));\n+                break;\n+            case 1:\n+                builder.topLeft(GeohashUtils.encodeLatLon(box.getMaxY(), box.getMinX()));\n+                break;\n+            default:\n+                builder.topLeft(box.getMaxY(), box.getMinX());\n+            }\n+\n+            path = randomIntBetween(0, 2);\n+            switch (path) {\n+            case 0:\n+                builder.bottomRight(new GeoPoint(box.getMinY(), box.getMaxX()));\n+                break;\n+            case 1:\n+                builder.bottomRight(GeohashUtils.encodeLatLon(box.getMinY(), box.getMaxX()));\n+            default:\n+                builder.bottomRight(box.getMinY(), box.getMaxX());\n+            }\n+        } else {\n+            // check the deprecated top-right/bottom-left combination of setters\n+            int path = randomIntBetween(0, 2);\n+            switch (path) {\n+            case 0:\n+                builder.topRight(new GeoPoint(box.getMaxY(), box.getMaxX()));\n+                break;\n+            case 1:\n+                builder.topRight(GeohashUtils.encodeLatLon(box.getMaxY(), box.getMaxX()));\n+                break;\n+            default:\n+                builder.topRight(box.getMaxY(), box.getMaxX());\n+            }\n+\n+            path = randomIntBetween(0, 2);\n+            switch (path) {\n+            case 0:\n+                builder.bottomLeft(new GeoPoint(box.getMinY(), box.getMinX()));\n+                break;\n+            case 1:\n+                builder.bottomLeft(GeohashUtils.encodeLatLon(box.getMinY(), box.getMinX()));\n+            default:\n+                builder.bottomLeft(box.getMinY(), box.getMinX());\n+            }\n+        }\n+\n+        if (randomBoolean()) {\n+            builder.coerce(randomBoolean());\n+        }\n+        if (randomBoolean()) {\n+            builder.ignoreMalformed(randomBoolean());\n+        }\n+\n+        if (randomBoolean()) {\n+            builder.type(Type.MEMORY);\n+        } else {\n+            builder.type(Type.INDEXED);\n+        }\n+        return builder;\n+    }\n+\n+    @Test(expected = IllegalArgumentException.class)\n+    public void testValidation_empty_fieldname() {\n+        new GeoBoundingBoxQueryBuilder(\"\");\n+    }\n+    @Test(expected = IllegalArgumentException.class)\n+    public void testValidation_null_fieldname() {\n+        new GeoBoundingBoxQueryBuilder(null);\n+    }\n+\n+    @Test\n+    public void testValidation() {\n+\n+        PointTester[] testers = { new TopTester(), new LeftTester(), new BottomTester(), new RightTester() };\n+        for (PointTester tester : testers) {\n+            GeoBoundingBoxQueryBuilder builder = createTestQueryBuilder();\n+            QueryValidationException except = null;\n+            builder = tester.invalidateCoordinate(builder);\n+            except = builder.coerce(true).validate(true);\n+            assertNull(\"Inner post 2.0 validation w/ coerce should ignore invalid top coordinate: \" + tester.getInvalidCoordinate() + \" \",\n+                    except);\n+\n+            except = builder.coerce(true).validate(false);\n+            assertNull(\"Inner pre 2.0 validation w/ coerce should ignore invalid top coordinate: \" + tester.getInvalidCoordinate() + \" \",\n+                    except);\n+\n+            except = builder.coerce(true).validate();\n+            assertNull(\"Validation w/ coerce should detect invalid top coordinate: \" + tester.getInvalidCoordinate() + \" \", except);\n+\n+            except = builder.coerce(false).ignoreMalformed(false).validate(false);\n+            assertEquals(\"Inner post 2.0 validation w/o coerce should ignore invalid top coordinate: \" + tester.getInvalidCoordinate(),\n+                    1,\n+                    except.validationErrors().size());\n+\n+            except = builder.coerce(false).ignoreMalformed(false).validate(true);\n+            assertNull(\"Inner pre 2.0 validation w/o coerce should ignore invalid top coordinate: \" + tester.getInvalidCoordinate(),\n+                    except);\n+\n+            except = builder.coerce(false).ignoreMalformed(false).validate();\n+            assertNull(\"Validation w/o coerce should ignore invalid top coordinate: \" + tester.getInvalidCoordinate(),\n+                    except);\n+\n+            double brokenDouble = randomFrom(invalidDoubles);\n+            tester.breakCoordinate(brokenDouble, builder);\n+            except = builder.coerce(true).validate(false);\n+            assertNull(\"Inner post 2.0 validation should not detect broken coordinates: \" + brokenDouble,\n+                    except);\n+\n+            except = builder.coerce(true).validate(true);\n+            assertNull(\"Inner pre 2.0 validation should not detect broken coordinates: \" + brokenDouble,\n+                    except);\n+\n+            except = builder.coerce(true).validate();\n+            assertNull(\"Validation w/ coerce should detect broken top coordinate: \" + brokenDouble, \n+                    except);\n+\n+            except = builder.coerce(false).ignoreMalformed(false).validate(false);\n+            assertEquals(\"Inner post 2.0 validation should detect broken coordinates: \" + brokenDouble,\n+                    1,\n+                    except.validationErrors().size());\n+\n+            except = builder.coerce(false).ignoreMalformed(false).validate(true);\n+            assertNull(\"Inner pre 2.0 validation should not detect broken coordinates: \" + brokenDouble,\n+                    except);\n+\n+            except = builder.coerce(false).ignoreMalformed(false).validate();\n+            assertEquals(\n+                    \"Validation w/o normalization should detect broken top coordinate: \" + brokenDouble + \" \" + except.validationErrors(),\n+                    1, except.validationErrors().size());\n+        }\n+\n+        // flipping top and bottom should be detected as error\n+        GeoBoundingBoxQueryBuilder builder = createTestQueryBuilder();\n+        double top = builder.topLeft().getLat();\n+        double left = builder.topLeft().getLon();\n+        double bottom = builder.bottomRight().getLat();\n+        double right = builder.bottomRight().getLon();\n+\n+        builder.topLeft(bottom, left).bottomRight(top, right);\n+\n+        builder.coerce(true);\n+        assertNull(\"Validation w/ coerce should not detect flipped topLeft/bottomRight lat corners: \" + \"topLeft: \" + builder.topLeft() + \" vs. bottomRight:\"\n+                + builder.bottomRight() + \" \", builder.validate());\n+        assertNull(\"Inner validation should not check for flipped lat corners.\", builder.validate(true));\n+        assertNull(\"Inner validation should not check for flipped lat corners.\", builder.validate(false));\n+\n+        builder.coerce(false).ignoreMalformed(false);\n+        assertNotNull(\"Validation should not detect flipped topLeft/bottomRight lat corners: \" + \"topLeft: \" + builder.topLeft() + \" vs. bottomRight:\"\n+                + builder.bottomRight() + \" \", builder.validate());\n+        assertNull(\"Inner validation should not check for flipped lat corners.\", builder.validate(true));\n+        assertNull(\"Inner validation should not check for flipped lat corners.\", builder.validate(false));\n+\n+        // flipping left and right should be allowed\n+        builder.topLeft(top, right).bottomRight(bottom, left);\n+        builder.coerce(true);\n+        assertNull(\"Validation should not detect flipped topLeft/bottomRight lon corners: \" + \"topLeft: \" + builder.topLeft() + \" vs. bottomRight:\"\n+                + builder.bottomRight() + \" \", builder.validate(false));\n+        assertNull(\"Inner validation should not check for flipped lat corners.\", builder.validate(true));\n+        assertNull(\"Inner validation should not check for flipped lat corners.\", builder.validate(false));\n+\n+        builder.coerce(false).ignoreMalformed(false);\n+        assertNull(\"Validation should not detect flipped topLeft/bottomRight lon corners: \" + \"topLeft: \" + builder.topLeft() + \" vs. bottomRight:\"\n+                + builder.bottomRight() + \" \", builder.validate(false));\n+        assertNull(\"Inner validation should not check for flipped lat corners.\", builder.validate(true));\n+        assertNull(\"Inner validation should not check for flipped lat corners.\", builder.validate(false));\n+    }\n+\n+    @Test\n+    public void testNormalization() throws IOException {\n+        GeoBoundingBoxQueryBuilder qb = createTestQueryBuilder();\n+        if (getCurrentTypes().length != 0 && \"mapped_geo\".equals(qb.fieldName())) {\n+            // only execute this test if we are running on a valid geo field\n+            qb.topLeft(200, 200);\n+            qb.coerce(true);\n+            Query query = qb.toQuery(createShardContext());\n+            if (query instanceof ConstantScoreQuery) {\n+                ConstantScoreQuery result = (ConstantScoreQuery) query;\n+                BooleanQuery bboxFilter = (BooleanQuery) result.getQuery();\n+                for (BooleanClause clause : bboxFilter.clauses()) {\n+                    NumericRangeQuery boundary = (NumericRangeQuery) clause.getQuery();\n+                    if (boundary.getMax() != null) {\n+                        assertTrue(\"If defined, non of the maximum range values should be larger than 180\", boundary.getMax().intValue() <= 180);\n+                    }\n+                }\n+            } else {\n+                assertTrue(\"memory queries should result in InMemoryGeoBoundingBoxQuery\", query instanceof InMemoryGeoBoundingBoxQuery);\n+            }\n+        }\n+    }\n+\n+    @Override\n+    protected void doAssertLuceneQuery(GeoBoundingBoxQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException {\n+        if (getCurrentTypes().length == 0 || \"mapped_geo\".equals(queryBuilder.fieldName()) == false) {\n+            assertTrue(\"For non geo fields expect MatchNoDocsQuery.\", query instanceof MatchNoDocsQuery);\n+        } else if (queryBuilder.type() == Type.INDEXED) {\n+            assertTrue(\"Found no indexed geo query.\", query instanceof ConstantScoreQuery);\n+        } else {\n+            assertTrue(\"Found no indexed geo query.\", query instanceof InMemoryGeoBoundingBoxQuery);\n+        }\n+    }\n+\n+    // Java really could do with function pointers...\n+    private interface PointTester {","path":"core/src/test/java/org/elasticsearch/index/query/GeoBoundingBoxQueryBuilderTest.java","position":282,"original_position":282,"commit_id":"f58618dba23219c36a13fe64b25d898a46f2cc6d","original_commit_id":"f58618dba23219c36a13fe64b25d898a46f2cc6d","user":{"login":"javanna","id":832460,"avatar_url":"https://avatars.githubusercontent.com/u/832460?v=3","gravatar_id":"","url":"https://api.github.com/users/javanna","html_url":"https://github.com/javanna","followers_url":"https://api.github.com/users/javanna/followers","following_url":"https://api.github.com/users/javanna/following{/other_user}","gists_url":"https://api.github.com/users/javanna/gists{/gist_id}","starred_url":"https://api.github.com/users/javanna/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/javanna/subscriptions","organizations_url":"https://api.github.com/users/javanna/orgs","repos_url":"https://api.github.com/users/javanna/repos","events_url":"https://api.github.com/users/javanna/events{/privacy}","received_events_url":"https://api.github.com/users/javanna/received_events","type":"User","site_admin":false},"body":"nitpick: this could be an abstrat class instead and have a coordinate instance member rather than repeating it all over.","created_at":"2015-09-02T10:48:52Z","updated_at":"2015-09-02T10:48:52Z","html_url":"https://github.com/elastic/elasticsearch/pull/11969#discussion_r38519225","pull_request_url":"https://api.github.com/repos/elastic/elasticsearch/pulls/11969","_links":{"self":{"href":"https://api.github.com/repos/elastic/elasticsearch/pulls/comments/38519225"},"html":{"href":"https://github.com/elastic/elasticsearch/pull/11969#discussion_r38519225"},"pull_request":{"href":"https://api.github.com/repos/elastic/elasticsearch/pulls/11969"}}},"pull_request":{"url":"https://api.github.com/repos/elastic/elasticsearch/pulls/11969","id":38957660,"html_url":"https://github.com/elastic/elasticsearch/pull/11969","diff_url":"https://github.com/elastic/elasticsearch/pull/11969.diff","patch_url":"https://github.com/elastic/elasticsearch/pull/11969.patch","issue_url":"https://api.github.com/repos/elastic/elasticsearch/issues/11969","number":11969,"state":"open","locked":false,"title":"Refactoring of GeoBoundingBoxQueryBuilder and -Parser","user":{"login":"MaineC","id":70953,"avatar_url":"https://avatars.githubusercontent.com/u/70953?v=3","gravatar_id":"","url":"https://api.github.com/users/MaineC","html_url":"https://github.com/MaineC","followers_url":"https://api.github.com/users/MaineC/followers","following_url":"https://api.github.com/users/MaineC/following{/other_user}","gists_url":"https://api.github.com/users/MaineC/gists{/gist_id}","starred_url":"https://api.github.com/users/MaineC/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MaineC/subscriptions","organizations_url":"https://api.github.com/users/MaineC/orgs","repos_url":"https://api.github.com/users/MaineC/repos","events_url":"https://api.github.com/users/MaineC/events{/privacy}","received_events_url":"https://api.github.com/users/MaineC/received_events","type":"User","site_admin":false},"body":"... -Builder/-Parser. This add equals, hashcode, read/write methods, separates toQuery and JSON parsing and adds first tests.\r\n\r\nDeprecates two types of initializing the bounding box: In our documentation we speak about specifying top/left and bottom/right corner of a bounding box. Here we also allow for top/right and bottom/left. This adds not only to the amount of code but also testing needed w/o too much benefit for the user other than more chances to confuse top/right/bottom/left/latitude/longitude IMHO.\r\n\r\nMissing: validation, there are some easy opportunities for cleaning parser and builder.\r\n\r\nThe test path that checks the toQuery method if type is set to \"indexed\" fails at the moment due to missing Guice initialisations. I tried to add everything needed but felt like the result looked a lot like it would actually like to be an ElasticsearchSingleNodeTest so not sure how to proceed here?\r\n\r\nRelates to #10217","created_at":"2015-07-01T08:11:26Z","updated_at":"2015-09-02T10:48:52Z","closed_at":null,"merged_at":null,"merge_commit_sha":"011cd11ad2cae31b2507f72ae6df384a2ee08e88","assignee":{"login":"MaineC","id":70953,"avatar_url":"https://avatars.githubusercontent.com/u/70953?v=3","gravatar_id":"","url":"https://api.github.com/users/MaineC","html_url":"https://github.com/MaineC","followers_url":"https://api.github.com/users/MaineC/followers","following_url":"https://api.github.com/users/MaineC/following{/other_user}","gists_url":"https://api.github.com/users/MaineC/gists{/gist_id}","starred_url":"https://api.github.com/users/MaineC/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MaineC/subscriptions","organizations_url":"https://api.github.com/users/MaineC/orgs","repos_url":"https://api.github.com/users/MaineC/repos","events_url":"https://api.github.com/users/MaineC/events{/privacy}","received_events_url":"https://api.github.com/users/MaineC/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/elastic/elasticsearch/pulls/11969/commits","review_comments_url":"https://api.github.com/repos/elastic/elasticsearch/pulls/11969/comments","review_comment_url":"https://api.github.com/repos/elastic/elasticsearch/pulls/comments{/number}","comments_url":"https://api.github.com/repos/elastic/elasticsearch/issues/11969/comments","statuses_url":"https://api.github.com/repos/elastic/elasticsearch/statuses/f58618dba23219c36a13fe64b25d898a46f2cc6d","head":{"label":"MaineC:feature/geo-bounding-box-refactoring","ref":"feature/geo-bounding-box-refactoring","sha":"f58618dba23219c36a13fe64b25d898a46f2cc6d","user":{"login":"MaineC","id":70953,"avatar_url":"https://avatars.githubusercontent.com/u/70953?v=3","gravatar_id":"","url":"https://api.github.com/users/MaineC","html_url":"https://github.com/MaineC","followers_url":"https://api.github.com/users/MaineC/followers","following_url":"https://api.github.com/users/MaineC/following{/other_user}","gists_url":"https://api.github.com/users/MaineC/gists{/gist_id}","starred_url":"https://api.github.com/users/MaineC/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MaineC/subscriptions","organizations_url":"https://api.github.com/users/MaineC/orgs","repos_url":"https://api.github.com/users/MaineC/repos","events_url":"https://api.github.com/users/MaineC/events{/privacy}","received_events_url":"https://api.github.com/users/MaineC/received_events","type":"User","site_admin":false},"repo":{"id":14859176,"name":"elasticsearch","full_name":"MaineC/elasticsearch","owner":{"login":"MaineC","id":70953,"avatar_url":"https://avatars.githubusercontent.com/u/70953?v=3","gravatar_id":"","url":"https://api.github.com/users/MaineC","html_url":"https://github.com/MaineC","followers_url":"https://api.github.com/users/MaineC/followers","following_url":"https://api.github.com/users/MaineC/following{/other_user}","gists_url":"https://api.github.com/users/MaineC/gists{/gist_id}","starred_url":"https://api.github.com/users/MaineC/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MaineC/subscriptions","organizations_url":"https://api.github.com/users/MaineC/orgs","repos_url":"https://api.github.com/users/MaineC/repos","events_url":"https://api.github.com/users/MaineC/events{/privacy}","received_events_url":"https://api.github.com/users/MaineC/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/MaineC/elasticsearch","description":"Open Source, Distributed, RESTful Search Engine","fork":true,"url":"https://api.github.com/repos/MaineC/elasticsearch","forks_url":"https://api.github.com/repos/MaineC/elasticsearch/forks","keys_url":"https://api.github.com/repos/MaineC/elasticsearch/keys{/key_id}","collaborators_url":"https://api.github.com/repos/MaineC/elasticsearch/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/MaineC/elasticsearch/teams","hooks_url":"https://api.github.com/repos/MaineC/elasticsearch/hooks","issue_events_url":"https://api.github.com/repos/MaineC/elasticsearch/issues/events{/number}","events_url":"https://api.github.com/repos/MaineC/elasticsearch/events","assignees_url":"https://api.github.com/repos/MaineC/elasticsearch/assignees{/user}","branches_url":"https://api.github.com/repos/MaineC/elasticsearch/branches{/branch}","tags_url":"https://api.github.com/repos/MaineC/elasticsearch/tags","blobs_url":"https://api.github.com/repos/MaineC/elasticsearch/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/MaineC/elasticsearch/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/MaineC/elasticsearch/git/refs{/sha}","trees_url":"https://api.github.com/repos/MaineC/elasticsearch/git/trees{/sha}","statuses_url":"https://api.github.com/repos/MaineC/elasticsearch/statuses/{sha}","languages_url":"https://api.github.com/repos/MaineC/elasticsearch/languages","stargazers_url":"https://api.github.com/repos/MaineC/elasticsearch/stargazers","contributors_url":"https://api.github.com/repos/MaineC/elasticsearch/contributors","subscribers_url":"https://api.github.com/repos/MaineC/elasticsearch/subscribers","subscription_url":"https://api.github.com/repos/MaineC/elasticsearch/subscription","commits_url":"https://api.github.com/repos/MaineC/elasticsearch/commits{/sha}","git_commits_url":"https://api.github.com/repos/MaineC/elasticsearch/git/commits{/sha}","comments_url":"https://api.github.com/repos/MaineC/elasticsearch/comments{/number}","issue_comment_url":"https://api.github.com/repos/MaineC/elasticsearch/issues/comments{/number}","contents_url":"https://api.github.com/repos/MaineC/elasticsearch/contents/{+path}","compare_url":"https://api.github.com/repos/MaineC/elasticsearch/compare/{base}...{head}","merges_url":"https://api.github.com/repos/MaineC/elasticsearch/merges","archive_url":"https://api.github.com/repos/MaineC/elasticsearch/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/MaineC/elasticsearch/downloads","issues_url":"https://api.github.com/repos/MaineC/elasticsearch/issues{/number}","pulls_url":"https://api.github.com/repos/MaineC/elasticsearch/pulls{/number}","milestones_url":"https://api.github.com/repos/MaineC/elasticsearch/milestones{/number}","notifications_url":"https://api.github.com/repos/MaineC/elasticsearch/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/MaineC/elasticsearch/labels{/name}","releases_url":"https://api.github.com/repos/MaineC/elasticsearch/releases{/id}","created_at":"2013-12-02T10:17:35Z","updated_at":"2015-05-06T09:43:46Z","pushed_at":"2015-09-01T09:54:55Z","git_url":"git://github.com/MaineC/elasticsearch.git","ssh_url":"git@github.com:MaineC/elasticsearch.git","clone_url":"https://github.com/MaineC/elasticsearch.git","svn_url":"https://github.com/MaineC/elasticsearch","homepage":"http://elasticsearch.org","size":130526,"stargazers_count":0,"watchers_count":0,"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":0,"default_branch":"master"}},"base":{"label":"elastic:feature/query-refactoring","ref":"feature/query-refactoring","sha":"95f38171827d534afd7922b4a9aa12188418f1d3","user":{"login":"elastic","id":6764390,"avatar_url":"https://avatars.githubusercontent.com/u/6764390?v=3","gravatar_id":"","url":"https://api.github.com/users/elastic","html_url":"https://github.com/elastic","followers_url":"https://api.github.com/users/elastic/followers","following_url":"https://api.github.com/users/elastic/following{/other_user}","gists_url":"https://api.github.com/users/elastic/gists{/gist_id}","starred_url":"https://api.github.com/users/elastic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/elastic/subscriptions","organizations_url":"https://api.github.com/users/elastic/orgs","repos_url":"https://api.github.com/users/elastic/repos","events_url":"https://api.github.com/users/elastic/events{/privacy}","received_events_url":"https://api.github.com/users/elastic/received_events","type":"Organization","site_admin":false},"repo":{"id":507775,"name":"elasticsearch","full_name":"elastic/elasticsearch","owner":{"login":"elastic","id":6764390,"avatar_url":"https://avatars.githubusercontent.com/u/6764390?v=3","gravatar_id":"","url":"https://api.github.com/users/elastic","html_url":"https://github.com/elastic","followers_url":"https://api.github.com/users/elastic/followers","following_url":"https://api.github.com/users/elastic/following{/other_user}","gists_url":"https://api.github.com/users/elastic/gists{/gist_id}","starred_url":"https://api.github.com/users/elastic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/elastic/subscriptions","organizations_url":"https://api.github.com/users/elastic/orgs","repos_url":"https://api.github.com/users/elastic/repos","events_url":"https://api.github.com/users/elastic/events{/privacy}","received_events_url":"https://api.github.com/users/elastic/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/elastic/elasticsearch","description":"Open Source, Distributed, RESTful Search Engine","fork":false,"url":"https://api.github.com/repos/elastic/elasticsearch","forks_url":"https://api.github.com/repos/elastic/elasticsearch/forks","keys_url":"https://api.github.com/repos/elastic/elasticsearch/keys{/key_id}","collaborators_url":"https://api.github.com/repos/elastic/elasticsearch/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/elastic/elasticsearch/teams","hooks_url":"https://api.github.com/repos/elastic/elasticsearch/hooks","issue_events_url":"https://api.github.com/repos/elastic/elasticsearch/issues/events{/number}","events_url":"https://api.github.com/repos/elastic/elasticsearch/events","assignees_url":"https://api.github.com/repos/elastic/elasticsearch/assignees{/user}","branches_url":"https://api.github.com/repos/elastic/elasticsearch/branches{/branch}","tags_url":"https://api.github.com/repos/elastic/elasticsearch/tags","blobs_url":"https://api.github.com/repos/elastic/elasticsearch/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/elastic/elasticsearch/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/elastic/elasticsearch/git/refs{/sha}","trees_url":"https://api.github.com/repos/elastic/elasticsearch/git/trees{/sha}","statuses_url":"https://api.github.com/repos/elastic/elasticsearch/statuses/{sha}","languages_url":"https://api.github.com/repos/elastic/elasticsearch/languages","stargazers_url":"https://api.github.com/repos/elastic/elasticsearch/stargazers","contributors_url":"https://api.github.com/repos/elastic/elasticsearch/contributors","subscribers_url":"https://api.github.com/repos/elastic/elasticsearch/subscribers","subscription_url":"https://api.github.com/repos/elastic/elasticsearch/subscription","commits_url":"https://api.github.com/repos/elastic/elasticsearch/commits{/sha}","git_commits_url":"https://api.github.com/repos/elastic/elasticsearch/git/commits{/sha}","comments_url":"https://api.github.com/repos/elastic/elasticsearch/comments{/number}","issue_comment_url":"https://api.github.com/repos/elastic/elasticsearch/issues/comments{/number}","contents_url":"https://api.github.com/repos/elastic/elasticsearch/contents/{+path}","compare_url":"https://api.github.com/repos/elastic/elasticsearch/compare/{base}...{head}","merges_url":"https://api.github.com/repos/elastic/elasticsearch/merges","archive_url":"https://api.github.com/repos/elastic/elasticsearch/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/elastic/elasticsearch/downloads","issues_url":"https://api.github.com/repos/elastic/elasticsearch/issues{/number}","pulls_url":"https://api.github.com/repos/elastic/elasticsearch/pulls{/number}","milestones_url":"https://api.github.com/repos/elastic/elasticsearch/milestones{/number}","notifications_url":"https://api.github.com/repos/elastic/elasticsearch/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/elastic/elasticsearch/labels{/name}","releases_url":"https://api.github.com/repos/elastic/elasticsearch/releases{/id}","created_at":"2010-02-08T13:20:56Z","updated_at":"2015-09-02T08:33:04Z","pushed_at":"2015-09-02T10:47:16Z","git_url":"git://github.com/elastic/elasticsearch.git","ssh_url":"git@github.com:elastic/elasticsearch.git","clone_url":"https://github.com/elastic/elasticsearch.git","svn_url":"https://github.com/elastic/elasticsearch","homepage":"https://www.elastic.co/products/elasticsearch","size":414734,"stargazers_count":12571,"watchers_count":12571,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":4055,"mirror_url":null,"open_issues_count":1193,"forks":4055,"open_issues":1193,"watchers":12571,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/elastic/elasticsearch/pulls/11969"},"html":{"href":"https://github.com/elastic/elasticsearch/pull/11969"},"issue":{"href":"https://api.github.com/repos/elastic/elasticsearch/issues/11969"},"comments":{"href":"https://api.github.com/repos/elastic/elasticsearch/issues/11969/comments"},"review_comments":{"href":"https://api.github.com/repos/elastic/elasticsearch/pulls/11969/comments"},"review_comment":{"href":"https://api.github.com/repos/elastic/elasticsearch/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/elastic/elasticsearch/pulls/11969/commits"},"statuses":{"href":"https://api.github.com/repos/elastic/elasticsearch/statuses/f58618dba23219c36a13fe64b25d898a46f2cc6d"}}}}