diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search/160_exists_query.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/search/160_exists_query.yml index 1faf2eaa676e2..7c87d4f580bb9 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/search/160_exists_query.yml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search/160_exists_query.yml @@ -1346,15 +1346,13 @@ setup: index: json_test body: mappings: - _doc: - dynamic: false - properties: - json: - type: json + dynamic: false + properties: + json: + type: json - do: index: index: json_test - type: _doc id: 1 body: json: @@ -1369,7 +1367,7 @@ setup: exists: field: json - - match: { hits.total: 1 } + - match: { hits.total.value: 1 } - do: search: @@ -1379,7 +1377,7 @@ setup: exists: field: json.key - - match: { hits.total: 1 } + - match: { hits.total.value: 1 } - do: search: @@ -1389,4 +1387,4 @@ setup: exists: field: json.nonexistent_key - - match: { hits.total: 0 } + - match: { hits.total.value: 0 } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search/60_query_string.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/search/60_query_string.yml index b5742e2235846..b35cff3a831ad 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/search/60_query_string.yml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search/60_query_string.yml @@ -73,15 +73,13 @@ index: test body: mappings: - _doc: - properties: - headers: - type: json + properties: + headers: + type: json - do: index: index: test - type: _doc id: 1 body: headers: @@ -92,7 +90,6 @@ - do: index: index: test - type: _doc id: 2 body: headers: @@ -108,7 +105,7 @@ query_string: query: "headers:text\\/plain" - - match: { hits.total: 1 } + - match: { hits.total.value: 1 } - length: { hits.hits: 1 } - match: { hits.hits.0._id: "2" } @@ -120,6 +117,6 @@ query_string: query: "application\\/javascript AND headers.origin:elastic.co" - - match: { hits.total: 1 } + - match: { hits.total.value: 1 } - length: { hits.hits: 1 } - match: { hits.hits.0._id: "1" } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/JsonFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/JsonFieldMapper.java index 76e80a7d4b2e6..c96fa170b48c4 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/JsonFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/JsonFieldMapper.java @@ -29,6 +29,7 @@ import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.Version; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.lucene.Lucene; import org.elasticsearch.common.settings.Settings; @@ -165,6 +166,11 @@ public Builder copyTo(CopyTo copyTo) { throw new UnsupportedOperationException("[copy_to] is not supported for [" + CONTENT_TYPE + "] fields."); } + @Override + protected boolean defaultDocValues(Version indexCreated) { + return false; + } + @Override public JsonFieldMapper build(BuilderContext context) { setupFieldType(context); @@ -276,6 +282,25 @@ public Query existsQuery(QueryShardContext context) { return new PrefixQuery(term); } + @Override + public Query rangeQuery(Object lowerTerm, + Object upperTerm, + boolean includeLower, + boolean includeUpper, + QueryShardContext context) { + + // We require range queries to specify both bounds because an unbounded query could incorrectly match + // values from other keys. For example, a query on the 'first' key with only a lower bound would become + // ("first\0value", null), which would also match the value "second\0value" belonging to the key 'second'. + if (lowerTerm == null || upperTerm == null) { + throw new IllegalArgumentException("[range] queries on keyed [" + CONTENT_TYPE + + "] fields must include both an upper and a lower bound."); + } + + return super.rangeQuery(lowerTerm, upperTerm, + includeLower, includeUpper, context); + } + @Override public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { diff --git a/server/src/test/java/org/elasticsearch/index/mapper/JsonFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/JsonFieldMapperTests.java index 77dbe5d33fc18..13bdbd4cd97f2 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/JsonFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/JsonFieldMapperTests.java @@ -30,6 +30,7 @@ import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.index.IndexService; +import org.elasticsearch.index.mapper.JsonFieldMapper.KeyedJsonFieldType; import org.elasticsearch.index.mapper.JsonFieldMapper.RootJsonFieldType; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.test.ESSingleNodeTestCase; @@ -42,7 +43,6 @@ import static org.apache.lucene.analysis.BaseTokenStreamTestCase.assertTokenStreamContents; import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.instanceOf; public class JsonFieldMapperTests extends ESSingleNodeTestCase { private IndexService indexService; @@ -417,7 +417,8 @@ public void testNullValues() throws Exception { assertEquals(new BytesRef("key\0placeholder"), prefixedOtherFields[0].binaryValue()); } - public void testSplitQueriesOnWhitespace() throws IOException { + public void testSplitQueriesOnWhitespace() throws IOException { + MapperService mapperService = indexService.mapperService(); String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject() .startObject("type") .startObject("properties") @@ -427,13 +428,16 @@ public void testSplitQueriesOnWhitespace() throws IOException { .endObject() .endObject() .endObject().endObject()); - indexService.mapperService().merge("type", new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE); + mapperService.merge("type", new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE); - MappedFieldType fieldType = indexService.mapperService().fullName("field"); - assertThat(fieldType, instanceOf(RootJsonFieldType.class)); + RootJsonFieldType rootFieldType = (RootJsonFieldType) mapperService.fullName("field"); + assertThat(rootFieldType.searchAnalyzer(), equalTo(JsonFieldMapper.WHITESPACE_ANALYZER)); + assertTokenStreamContents(rootFieldType.searchAnalyzer().analyzer().tokenStream("", "Hello World"), + new String[] {"Hello", "World"}); - RootJsonFieldType ft = (RootJsonFieldType) fieldType; - assertThat(ft.searchAnalyzer(), equalTo(JsonFieldMapper.WHITESPACE_ANALYZER)); - assertTokenStreamContents(ft.searchAnalyzer().analyzer().tokenStream("", "Hello World"), new String[] {"Hello", "World"}); + KeyedJsonFieldType keyedFieldType = (KeyedJsonFieldType) mapperService.fullName("field.key"); + assertThat(keyedFieldType.searchAnalyzer(), equalTo(JsonFieldMapper.WHITESPACE_ANALYZER)); + assertTokenStreamContents(keyedFieldType.searchAnalyzer().analyzer().tokenStream("", "Hello World"), + new String[] {"Hello", "World"}); } } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/KeyedJsonFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/KeyedJsonFieldTypeTests.java index 25ad20805844a..2063556b9fbda 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/KeyedJsonFieldTypeTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/KeyedJsonFieldTypeTests.java @@ -20,14 +20,20 @@ import org.apache.lucene.index.IndexOptions; import org.apache.lucene.index.Term; +import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.TermInSetQuery; import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.TermRangeQuery; import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.index.mapper.JsonFieldMapper.KeyedJsonFieldType; import org.junit.Before; +import java.util.ArrayList; +import java.util.List; + public class KeyedJsonFieldTypeTests extends FieldTypeTestCase { @Before @@ -73,6 +79,22 @@ public void testTermQuery() { assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage()); } + public void testTermsQuery() { + KeyedJsonFieldType ft = createDefaultFieldType(); + ft.setName("field"); + + Query expected = new TermInSetQuery("field", + new BytesRef("key\0value1"), + new BytesRef("key\0value2")); + + List terms = new ArrayList<>(); + terms.add("value1"); + terms.add("value2"); + Query actual = ft.termsQuery(terms, null); + + assertEquals(expected, actual); + } + public void testExistsQuery() { KeyedJsonFieldType ft = createDefaultFieldType(); ft.setName("field"); @@ -81,6 +103,14 @@ public void testExistsQuery() { assertEquals(expected, ft.existsQuery(null)); } + public void testPrefixQuery() { + KeyedJsonFieldType ft = createDefaultFieldType(); + ft.setName("field"); + + Query expected = new PrefixQuery(new Term("field", "key\0val")); + assertEquals(expected, ft.prefixQuery("val", MultiTermQuery.CONSTANT_SCORE_REWRITE, null)); + } + public void testFuzzyQuery() { KeyedJsonFieldType ft = createDefaultFieldType(); ft.setName("field"); @@ -90,6 +120,31 @@ public void testFuzzyQuery() { assertEquals("[fuzzy] queries are not currently supported on [json] fields.", e.getMessage()); } + public void testRangeQuery() { + KeyedJsonFieldType ft = createDefaultFieldType(); + ft.setName("field"); + + TermRangeQuery expected = new TermRangeQuery("field", + new BytesRef("key\0lower"), + new BytesRef("key\0upper"), false, false); + assertEquals(expected, ft.rangeQuery("lower", "upper", false, false, null)); + + expected = new TermRangeQuery("field", + new BytesRef("key\0lower"), + new BytesRef("key\0upper"), true, true); + assertEquals(expected, ft.rangeQuery("lower", "upper", true, true, null)); + + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> + ft.rangeQuery("lower", null, false, false, null)); + assertEquals("[range] queries on keyed [json] fields must include both an upper and a lower bound.", + e.getMessage()); + + e = expectThrows(IllegalArgumentException.class, () -> + ft.rangeQuery(null, "upper", false, false, null)); + assertEquals("[range] queries on keyed [json] fields must include both an upper and a lower bound.", + e.getMessage()); + } + public void testRegexpQuery() { KeyedJsonFieldType ft = createDefaultFieldType(); ft.setName("field"); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/RootJsonFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/RootJsonFieldTypeTests.java index 06ab215a04737..c5eb01dc0cbf5 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/RootJsonFieldTypeTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/RootJsonFieldTypeTests.java @@ -22,6 +22,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.TermRangeQuery; import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.index.mapper.JsonFieldMapper.RootJsonFieldType; @@ -83,6 +84,21 @@ public void testFuzzyQuery() { assertEquals("[fuzzy] queries are not currently supported on [json] fields.", e.getMessage()); } + public void testRangeQuery() { + RootJsonFieldType ft = createDefaultFieldType(); + ft.setName("field"); + + TermRangeQuery expected = new TermRangeQuery("field", + new BytesRef("lower"), + new BytesRef("upper"), false, false); + assertEquals(expected, ft.rangeQuery("lower", "upper", false, false, null)); + + expected = new TermRangeQuery("field", + new BytesRef("lower"), + new BytesRef("upper"), true, true); + assertEquals(expected, ft.rangeQuery("lower", "upper", true, true, null)); + } + public void testRegexpQuery() { RootJsonFieldType ft = createDefaultFieldType(); ft.setName("field"); diff --git a/server/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java index c258cce6c7c50..60b06073ec967 100644 --- a/server/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java @@ -65,7 +65,7 @@ public class MatchQueryBuilderTests extends AbstractQueryTestCase query.parse(Type.PHRASE, STRING_FIELD_NAME, "")); } - + private static class MockGraphAnalyzer extends Analyzer { CannedBinaryTokenStream tokenStream; diff --git a/server/src/test/java/org/elasticsearch/index/query/MultiMatchQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/MultiMatchQueryBuilderTests.java index 36ba370939b17..f80eb5ee82b28 100644 --- a/server/src/test/java/org/elasticsearch/index/query/MultiMatchQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/MultiMatchQueryBuilderTests.java @@ -65,7 +65,7 @@ public class MultiMatchQueryBuilderTests extends AbstractQueryTestCase indexRequests = getIndexRequests(); indexRandom(true, false, indexRequests); - MatchPhraseQueryBuilder baseQuery = QueryBuilders.matchPhraseQuery("name", "the who") + MatchPhraseQueryBuilder baseQuery = matchPhraseQuery("name", "the who") .analyzer("standard_stopwords"); MatchPhraseQueryBuilder matchNoneQuery = baseQuery.zeroTermsQuery(ZeroTermsQuery.NONE); @@ -67,7 +67,6 @@ public void testZeroTermsQuery() throws ExecutionException, InterruptedException assertHitCount(matchAllResponse, 2L); } - private List getIndexRequests() { List requests = new ArrayList<>(); requests.add(client().prepareIndex(INDEX, "band").setSource("name", "the beatles")); diff --git a/server/src/test/java/org/elasticsearch/search/query/ExistsIT.java b/server/src/test/java/org/elasticsearch/search/query/ExistsIT.java index 114060683219c..69936b940f5c8 100644 --- a/server/src/test/java/org/elasticsearch/search/query/ExistsIT.java +++ b/server/src/test/java/org/elasticsearch/search/query/ExistsIT.java @@ -39,6 +39,7 @@ import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; +import static org.elasticsearch.index.query.QueryBuilders.existsQuery; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse; @@ -231,4 +232,41 @@ public void testFieldAliasWithNoDocValues() throws Exception { assertSearchResponse(response); assertHitCount(response, 2); } + + public void testJsonFields() throws Exception { + XContentBuilder mapping = XContentFactory.jsonBuilder().startObject() + .startObject("type") + .startObject("properties") + .startObject("headers") + .field("type", "json") + .endObject() + .endObject() + .endObject() + .endObject(); + assertAcked(prepareCreate("test").addMapping("type", mapping)); + + IndexRequestBuilder indexRequest = client().prepareIndex("test", "type", "1") + .setSource(XContentFactory.jsonBuilder() + .startObject() + .startObject("headers") + .field("content-type", "application/json") + .endObject() + .endObject()); + indexRandom(true, false, indexRequest); + + SearchResponse searchResponse = client().prepareSearch() + .setQuery(existsQuery("headers")) + .get(); + assertHitCount(searchResponse, 1L); + + searchResponse = client().prepareSearch() + .setQuery(existsQuery("headers.content-type")) + .get(); + assertHitCount(searchResponse, 1L); + + searchResponse = client().prepareSearch() + .setQuery(existsQuery("headers.nonexistent")) + .get(); + assertHitCount(searchResponse, 0L); + } } diff --git a/server/src/test/java/org/elasticsearch/search/query/MatchQueryIT.java b/server/src/test/java/org/elasticsearch/search/query/MatchQueryIT.java new file mode 100644 index 0000000000000..7f594d21545d3 --- /dev/null +++ b/server/src/test/java/org/elasticsearch/search/query/MatchQueryIT.java @@ -0,0 +1,71 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.elasticsearch.search.query; + +import org.elasticsearch.action.index.IndexRequestBuilder; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.test.ESIntegTestCase; + +import static org.elasticsearch.index.query.QueryBuilders.matchQuery; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; + +public class MatchQueryIT extends ESIntegTestCase { + + public void testJsonFields() throws Exception { + XContentBuilder mapping = XContentFactory.jsonBuilder().startObject() + .startObject("_doc") + .startObject("properties") + .startObject("headers") + .field("type", "json") + .field("split_queries_on_whitespace", true) + .endObject() + .endObject() + .endObject() + .endObject(); + assertAcked(prepareCreate("test").addMapping("_doc", mapping)); + + IndexRequestBuilder indexRequest = client().prepareIndex("test", "_doc", "1") + .setSource(XContentFactory.jsonBuilder() + .startObject() + .startObject("headers") + .field("content-type", "application/json") + .field("origin", "https://www.elastic.co") + .endObject() + .endObject()); + indexRandom(true, false, indexRequest); + + SearchResponse searchResponse = client().prepareSearch() + .setQuery(matchQuery("headers", "application/json")) + .get(); + assertHitCount(searchResponse, 1L); + + searchResponse = client().prepareSearch() + .setQuery(matchQuery("headers.content-type", "application/json text/plain")) + .get(); + assertHitCount(searchResponse, 1L); + + searchResponse = client().prepareSearch() + .setQuery(matchQuery("headers.origin", "application/json")) + .get(); + assertHitCount(searchResponse, 0L); + } +} diff --git a/server/src/test/java/org/elasticsearch/search/query/MultiMatchQueryIT.java b/server/src/test/java/org/elasticsearch/search/query/MultiMatchQueryIT.java index 76850a197d969..4b5bb1c16d799 100644 --- a/server/src/test/java/org/elasticsearch/search/query/MultiMatchQueryIT.java +++ b/server/src/test/java/org/elasticsearch/search/query/MultiMatchQueryIT.java @@ -19,7 +19,6 @@ package org.elasticsearch.search.query; import com.carrotsearch.randomizedtesting.generators.RandomPicks; - import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.search.SearchResponse; @@ -712,6 +711,45 @@ public void testFuzzyFieldLevelBoosting() throws InterruptedException, Execution assertThat(hits[0].getScore(), greaterThan(hits[1].getScore())); } + public void testJsonFields() throws Exception { + XContentBuilder mapping = XContentFactory.jsonBuilder().startObject() + .startObject("_doc") + .startObject("properties") + .startObject("headers") + .field("type", "json") + .field("split_queries_on_whitespace", true) + .endObject() + .endObject() + .endObject() + .endObject(); + assertAcked(prepareCreate("test_json").addMapping("_doc", mapping)); + + IndexRequestBuilder indexRequest = client().prepareIndex("test_json", "_doc", "1") + .setSource(XContentFactory.jsonBuilder() + .startObject() + .startObject("headers") + .field("content-type", "application/json") + .field("origin", "https://www.elastic.co") + .endObject() + .endObject()); + indexRandom(true, false, indexRequest); + + SearchResponse searchResponse = client().prepareSearch() + .setQuery(multiMatchQuery("application/json", "headers")) + .get(); + assertHitCount(searchResponse, 1L); + + searchResponse = client().prepareSearch() + .setQuery(multiMatchQuery("application/json text/plain", "headers.content-type")) + .get(); + assertHitCount(searchResponse, 1L); + + searchResponse = client().prepareSearch() + .setQuery(multiMatchQuery("application/json", "headers.origin")) + .get(); + assertHitCount(searchResponse, 0L); + } + private static void assertEquivalent(String query, SearchResponse left, SearchResponse right) { assertNoFailures(left); assertNoFailures(right); diff --git a/server/src/test/java/org/elasticsearch/search/query/QueryStringIT.java b/server/src/test/java/org/elasticsearch/search/query/QueryStringIT.java index 8d5933e6cfc75..06ce000b2cd31 100644 --- a/server/src/test/java/org/elasticsearch/search/query/QueryStringIT.java +++ b/server/src/test/java/org/elasticsearch/search/query/QueryStringIT.java @@ -24,6 +24,7 @@ import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.query.Operator; @@ -47,6 +48,7 @@ import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; @@ -359,6 +361,36 @@ public void testFieldAliasOnDisallowedFieldType() throws Exception { assertHits(response.getHits(), "1"); } + public void testJsonField() throws Exception { + IndexRequestBuilder indexRequest = client().prepareIndex("test", "_doc", "1") + .setSource(XContentFactory.jsonBuilder() + .startObject() + .startObject("f_json") + .field("field1", "value") + .field("field2", "2.718") + .endObject() + .endObject()); + indexRandom(true, false, indexRequest); + + SearchResponse response = client().prepareSearch("test") + .setQuery(queryStringQuery("f_json.field1:value")) + .get(); + assertSearchResponse(response); + assertHitCount(response, 1); + + response = client().prepareSearch("test") + .setQuery(queryStringQuery("f_json.field1:value AND f_json:2.718")) + .get(); + assertSearchResponse(response); + assertHitCount(response, 1); + + response = client().prepareSearch("test") + .setQuery(queryStringQuery("2.718").field("f_json.field2")) + .get(); + assertSearchResponse(response); + assertHitCount(response, 1); + } + private void assertHits(SearchHits hits, String... ids) { assertThat(hits.getTotalHits().value, equalTo((long) ids.length)); Set hitIds = new HashSet<>(); diff --git a/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java b/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java index c07e6eb333bea..d2c5f92646f72 100644 --- a/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java +++ b/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java @@ -1875,82 +1875,4 @@ public void testFieldAliasesForMetaFields() throws Exception { DocumentField field = hit.getFields().get("id-alias"); assertThat(field.getValue().toString(), equalTo("1")); } - - public void testJsonField() throws Exception { - XContentBuilder mapping = XContentFactory.jsonBuilder() - .startObject() - .startObject("type") - .startObject("properties") - .startObject("headers") - .field("type", "json") - .endObject() - .endObject() - .endObject() - .endObject(); - assertAcked(prepareCreate("test").addMapping("type", mapping)); - - XContentBuilder source = XContentFactory.jsonBuilder() - .startObject() - .startObject("headers") - .field("content-type", "application/json") - .endObject() - .endObject(); - IndexRequestBuilder indexRequest = client().prepareIndex("test", "type") - .setId("1") - .setRouting("custom") - .setSource(source); - indexRandom(true, false, indexRequest); - - SearchResponse searchResponse = client().prepareSearch() - .setQuery(prefixQuery("headers", "application/")) - .get(); - assertHitCount(searchResponse, 1L); - - searchResponse = client().prepareSearch() - .setQuery(existsQuery("headers")) - .get(); - assertHitCount(searchResponse, 1L); - } - - public void testJsonFieldWithKey() throws Exception { - XContentBuilder mapping = XContentFactory.jsonBuilder() - .startObject() - .startObject("type") - .startObject("properties") - .startObject("headers") - .field("type", "json") - .endObject() - .endObject() - .endObject() - .endObject(); - assertAcked(prepareCreate("test").addMapping("type", mapping)); - - XContentBuilder source = XContentFactory.jsonBuilder() - .startObject() - .startObject("headers") - .field("content-type", "application/json") - .field("origin", "https://www.elastic.co") - .endObject() - .endObject(); - IndexRequestBuilder indexRequest = client().prepareIndex("test", "type") - .setId("1") - .setRouting("custom") - .setSource(source); - indexRandom(true, false, indexRequest); - - SearchResponse searchResponse = client().prepareSearch() - .setQuery(prefixQuery("headers.content-type", "application/")) - .get(); - assertHitCount(searchResponse, 1L); - - searchResponse = client().prepareSearch() - .setQuery(prefixQuery("headers.origin", "application/")) - .get(); - assertHitCount(searchResponse, 0L); - - searchResponse = client().prepareSearch() - .setQuery(existsQuery("headers.content-type")) - .get(); - assertHitCount(searchResponse, 1L); - } } diff --git a/server/src/test/java/org/elasticsearch/search/query/SimpleQueryStringIT.java b/server/src/test/java/org/elasticsearch/search/query/SimpleQueryStringIT.java index 7f8ab4aa51567..0f09167d4f89d 100644 --- a/server/src/test/java/org/elasticsearch/search/query/SimpleQueryStringIT.java +++ b/server/src/test/java/org/elasticsearch/search/query/SimpleQueryStringIT.java @@ -69,6 +69,7 @@ import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHits; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.hasId; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; @@ -642,7 +643,6 @@ public void testFieldAliasWithWildcardField() throws Exception { assertHits(response.getHits(), "2", "3"); } - public void testFieldAliasOnDisallowedFieldType() throws Exception { String indexBody = copyToStringFromClasspath("/org/elasticsearch/search/query/all-query-index.json"); assertAcked(prepareCreate("test").setSource(indexBody, XContentType.JSON)); @@ -663,6 +663,40 @@ public void testFieldAliasOnDisallowedFieldType() throws Exception { assertHits(response.getHits(), "1"); } + public void testJsonField() throws Exception { + String indexBody = copyToStringFromClasspath("/org/elasticsearch/search/query/all-query-index.json"); + assertAcked(prepareCreate("test").setSource(indexBody, XContentType.JSON)); + ensureGreen("test"); + + IndexRequestBuilder indexRequest = client().prepareIndex("test", "_doc", "1") + .setSource(XContentFactory.jsonBuilder() + .startObject() + .startObject("f_json") + .field("field1", "value") + .field("field2", "2.718") + .endObject() + .endObject()); + indexRandom(true, false, indexRequest); + + SearchResponse response = client().prepareSearch("test") + .setQuery(simpleQueryStringQuery("value").field("f_json.field1")) + .get(); + assertSearchResponse(response); + assertHitCount(response, 1); + + response = client().prepareSearch("test") + .setQuery(simpleQueryStringQuery("+value +2.718").field("f_json")) + .get(); + assertSearchResponse(response); + assertHitCount(response, 1); + + response = client().prepareSearch("test") + .setQuery(simpleQueryStringQuery("+value +3.141").field("f_json")) + .get(); + assertSearchResponse(response); + assertHitCount(response, 0); + } + private void assertHits(SearchHits hits, String... ids) { assertThat(hits.getTotalHits().value, equalTo((long) ids.length)); Set hitIds = new HashSet<>(); diff --git a/server/src/test/resources/org/elasticsearch/search/query/all-query-index.json b/server/src/test/resources/org/elasticsearch/search/query/all-query-index.json index 9ab8995813e33..208c88f2817b2 100644 --- a/server/src/test/resources/org/elasticsearch/search/query/all-query-index.json +++ b/server/src/test/resources/org/elasticsearch/search/query/all-query-index.json @@ -60,7 +60,8 @@ "type": "alias", "path": "f_geop" }, - "f_geos": {"type": "geo_shape"} + "f_geos": {"type": "geo_shape"}, + "f_json": {"type": "json"} } } } diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractBuilderTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractBuilderTestCase.java index 5eef0a249b687..d440b7f45289d 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractBuilderTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractBuilderTestCase.java @@ -113,13 +113,14 @@ public abstract class AbstractBuilderTestCase extends ESTestCase { protected static final String GEO_POINT_FIELD_NAME = "mapped_geo_point"; protected static final String GEO_POINT_ALIAS_FIELD_NAME = "mapped_geo_point_alias"; protected static final String GEO_SHAPE_FIELD_NAME = "mapped_geo_shape"; + protected static final String JSON_FIELD_NAME = "mapped_json"; protected static final String[] MAPPED_FIELD_NAMES = new String[]{STRING_FIELD_NAME, STRING_ALIAS_FIELD_NAME, INT_FIELD_NAME, INT_RANGE_FIELD_NAME, DOUBLE_FIELD_NAME, BOOLEAN_FIELD_NAME, DATE_FIELD_NAME, DATE_RANGE_FIELD_NAME, OBJECT_FIELD_NAME, GEO_POINT_FIELD_NAME, GEO_POINT_ALIAS_FIELD_NAME, - GEO_SHAPE_FIELD_NAME}; + GEO_SHAPE_FIELD_NAME, JSON_FIELD_NAME}; protected static final String[] MAPPED_LEAF_FIELD_NAMES = new String[]{STRING_FIELD_NAME, STRING_ALIAS_FIELD_NAME, INT_FIELD_NAME, INT_RANGE_FIELD_NAME, DOUBLE_FIELD_NAME, BOOLEAN_FIELD_NAME, - DATE_FIELD_NAME, DATE_RANGE_FIELD_NAME, GEO_POINT_FIELD_NAME, GEO_POINT_ALIAS_FIELD_NAME}; + DATE_FIELD_NAME, DATE_RANGE_FIELD_NAME, GEO_POINT_FIELD_NAME, GEO_POINT_ALIAS_FIELD_NAME, JSON_FIELD_NAME}; private static final Map ALIAS_TO_CONCRETE_FIELD_NAME = new HashMap<>(); static { @@ -396,7 +397,8 @@ public void onRemoval(ShardId shardId, Accountable accountable) { OBJECT_FIELD_NAME, "type=object", GEO_POINT_FIELD_NAME, "type=geo_point", GEO_POINT_ALIAS_FIELD_NAME, "type=alias,path=" + GEO_POINT_FIELD_NAME, - GEO_SHAPE_FIELD_NAME, "type=geo_shape" + GEO_SHAPE_FIELD_NAME, "type=geo_shape", + JSON_FIELD_NAME, "type=json" ))), MapperService.MergeReason.MAPPING_UPDATE); // also add mappings for two inner field in the object field mapperService.merge("_doc", new CompressedXContent("{\"properties\":{\"" + OBJECT_FIELD_NAME + "\":{\"type\":\"object\","