diff --git a/src/main/java/org/elasticsearch/index/fielddata/IndexFieldDataService.java b/src/main/java/org/elasticsearch/index/fielddata/IndexFieldDataService.java index 69588272d545d..7c4dd8cae4f8c 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/IndexFieldDataService.java +++ b/src/main/java/org/elasticsearch/index/fielddata/IndexFieldDataService.java @@ -35,6 +35,7 @@ import org.elasticsearch.index.fielddata.ordinals.InternalGlobalOrdinalsBuilder; import org.elasticsearch.index.fielddata.plain.*; import org.elasticsearch.index.mapper.FieldMapper; +import org.elasticsearch.index.mapper.internal.IndexFieldMapper; import org.elasticsearch.index.mapper.internal.ParentFieldMapper; import org.elasticsearch.index.service.IndexService; import org.elasticsearch.index.settings.IndexSettings; @@ -73,6 +74,7 @@ public class IndexFieldDataService extends AbstractIndexComponent { .put("long", new PackedArrayIndexFieldData.Builder().setNumericType(IndexNumericFieldData.NumericType.LONG)) .put("geo_point", new GeoPointDoubleArrayIndexFieldData.Builder()) .put(ParentFieldMapper.NAME, new ParentChildIndexFieldData.Builder()) + .put(IndexFieldMapper.NAME, new IndexIndexFieldData.Builder()) .put("binary", new DisabledIndexFieldData.Builder()) .immutableMap(); diff --git a/src/main/java/org/elasticsearch/index/fielddata/plain/IndexIndexFieldData.java b/src/main/java/org/elasticsearch/index/fielddata/plain/IndexIndexFieldData.java new file mode 100644 index 0000000000000..853eb006058e0 --- /dev/null +++ b/src/main/java/org/elasticsearch/index/fielddata/plain/IndexIndexFieldData.java @@ -0,0 +1,211 @@ +/* + * 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.index.fielddata.plain; + +import org.apache.lucene.index.AtomicReaderContext; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.TermsEnum; +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.index.Index; +import org.elasticsearch.index.fielddata.*; +import org.elasticsearch.index.fielddata.fieldcomparator.BytesRefFieldComparatorSource; +import org.elasticsearch.index.fielddata.ordinals.GlobalOrdinalsBuilder; +import org.elasticsearch.index.fielddata.ordinals.Ordinals; +import org.elasticsearch.index.mapper.FieldMapper; +import org.elasticsearch.index.mapper.MapperService; +import org.elasticsearch.indices.fielddata.breaker.CircuitBreakerService; +import org.elasticsearch.search.MultiValueMode; + +public class IndexIndexFieldData implements IndexFieldData.WithOrdinals> { + + public static class Builder implements IndexFieldData.Builder { + + @Override + public IndexFieldData build(Index index, Settings indexSettings, FieldMapper mapper, IndexFieldDataCache cache, + CircuitBreakerService breakerService, MapperService mapperService, GlobalOrdinalsBuilder globalOrdinalBuilder) { + return new IndexIndexFieldData(index, mapper.names()); + } + + } + + private static final Ordinals.Docs INDEX_ORDINALS = new Ordinals.Docs() { + + @Override + public int setDocument(int docId) { + return 1; + } + + @Override + public long nextOrd() { + return Ordinals.MIN_ORDINAL; + } + + @Override + public boolean isMultiValued() { + return false; + } + + @Override + public long getOrd(int docId) { + return Ordinals.MIN_ORDINAL; + } + + @Override + public long getMaxOrd() { + return 1; + } + + @Override + public long currentOrd() { + return Ordinals.MIN_ORDINAL; + } + }; + + private static class IndexBytesValues extends BytesValues.WithOrdinals { + + final int hash; + + protected IndexBytesValues(String index) { + super(INDEX_ORDINALS); + scratch.copyChars(index); + hash = scratch.hashCode(); + } + + @Override + public int currentValueHash() { + return hash; + } + + @Override + public BytesRef getValueByOrd(long ord) { + return scratch; + } + + } + + private static class IndexAtomicFieldData implements AtomicFieldData.WithOrdinals { + + private final String index; + + IndexAtomicFieldData(String index) { + this.index = index; + } + + @Override + public long getMemorySizeInBytes() { + return 0; + } + + @Override + public boolean isMultiValued() { + return false; + } + + @Override + public long getNumberUniqueValues() { + return 1; + } + + @Override + public BytesValues.WithOrdinals getBytesValues(boolean needsHashes) { + return new IndexBytesValues(index); + } + + @Override + public ScriptDocValues getScriptValues() { + return new ScriptDocValues.Strings(getBytesValues(false)); + } + + @Override + public void close() { + } + + @Override + public TermsEnum getTermsEnum() { + return new AtomicFieldDataWithOrdinalsTermsEnum(this); + } + + } + + private final FieldMapper.Names names; + private final Index index; + + private IndexIndexFieldData(Index index, FieldMapper.Names names) { + this.index = index; + this.names = names; + } + + @Override + public Index index() { + return index; + } + + @Override + public org.elasticsearch.index.mapper.FieldMapper.Names getFieldNames() { + return names; + } + + @Override + public FieldDataType getFieldDataType() { + return new FieldDataType("string"); + } + + @Override + public boolean valuesOrdered() { + return true; + } + + @Override + public org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource comparatorSource(Object missingValue, + MultiValueMode sortMode) { + return new BytesRefFieldComparatorSource(this, missingValue, sortMode); + } + + @Override + public void clear() { + } + + @Override + public void clear(IndexReader reader) { + } + + @Override + public AtomicFieldData.WithOrdinals load(AtomicReaderContext context) { + return new IndexAtomicFieldData(index().name()); + } + + @Override + public AtomicFieldData.WithOrdinals loadDirect(AtomicReaderContext context) + throws Exception { + return load(context); + } + + @Override + public IndexFieldData.WithOrdinals loadGlobal(IndexReader indexReader) { + return this; + } + + @Override + public IndexFieldData.WithOrdinals localGlobalDirect(IndexReader indexReader) throws Exception { + return loadGlobal(indexReader); + } + +} diff --git a/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java b/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java index 7aff7dfc5f4ab..11329a46ef7d0 100644 --- a/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java +++ b/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java @@ -290,4 +290,5 @@ public static Loading parse(String loading, Loading defaultValue) { boolean hasDocValues(); Loading normsLoading(Loading defaultLoading); + } diff --git a/src/main/java/org/elasticsearch/index/mapper/internal/IndexFieldMapper.java b/src/main/java/org/elasticsearch/index/mapper/internal/IndexFieldMapper.java index dc89140bf104f..3d336ae2aba55 100644 --- a/src/main/java/org/elasticsearch/index/mapper/internal/IndexFieldMapper.java +++ b/src/main/java/org/elasticsearch/index/mapper/internal/IndexFieldMapper.java @@ -136,7 +136,7 @@ public FieldType defaultFieldType() { @Override public FieldDataType defaultFieldDataType() { - return new FieldDataType("string"); + return new FieldDataType(IndexFieldMapper.NAME); } @Override @@ -225,4 +225,5 @@ public void merge(Mapper mergeWith, MergeContext mergeContext) throws MergeMappi } } } + } diff --git a/src/main/java/org/elasticsearch/search/facet/terms/TermsFacetParser.java b/src/main/java/org/elasticsearch/search/facet/terms/TermsFacetParser.java index 2e5befa69096d..9148c14be2ef2 100644 --- a/src/main/java/org/elasticsearch/search/facet/terms/TermsFacetParser.java +++ b/src/main/java/org/elasticsearch/search/facet/terms/TermsFacetParser.java @@ -34,7 +34,6 @@ import org.elasticsearch.search.facet.FacetExecutor; import org.elasticsearch.search.facet.FacetParser; import org.elasticsearch.search.facet.terms.doubles.TermsDoubleFacetExecutor; -import org.elasticsearch.search.facet.terms.index.IndexNameFacetExecutor; import org.elasticsearch.search.facet.terms.longs.TermsLongFacetExecutor; import org.elasticsearch.search.facet.terms.strings.FieldsTermsStringFacetExecutor; import org.elasticsearch.search.facet.terms.strings.ScriptTermsStringFieldFacetExecutor; @@ -151,10 +150,6 @@ public FacetExecutor parse(String facetName, XContentParser parser, SearchContex } } - if ("_index".equals(field)) { - return new IndexNameFacetExecutor(context.shardTarget().index(), comparatorType, size); - } - if (fieldsNames != null && fieldsNames.length == 1) { field = fieldsNames[0]; fieldsNames = null; diff --git a/src/main/java/org/elasticsearch/search/facet/terms/index/IndexNameFacetExecutor.java b/src/main/java/org/elasticsearch/search/facet/terms/index/IndexNameFacetExecutor.java deleted file mode 100644 index d0ad19fc85056..0000000000000 --- a/src/main/java/org/elasticsearch/search/facet/terms/index/IndexNameFacetExecutor.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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.facet.terms.index; - -import com.google.common.collect.Sets; -import org.apache.lucene.index.AtomicReaderContext; -import org.elasticsearch.search.facet.FacetExecutor; -import org.elasticsearch.search.facet.InternalFacet; -import org.elasticsearch.search.facet.terms.TermsFacet; -import org.elasticsearch.search.facet.terms.strings.InternalStringTermsFacet; - -import java.io.IOException; - -/** - * - */ -public class IndexNameFacetExecutor extends FacetExecutor { - - private final String indexName; - private final InternalStringTermsFacet.ComparatorType comparatorType; - private final int size; - - private int count = 0; - - public IndexNameFacetExecutor(String indexName, TermsFacet.ComparatorType comparatorType, int size) { - this.indexName = indexName; - this.comparatorType = comparatorType; - this.size = size; - } - - @Override - public Collector collector() { - return new Collector(); - } - - @Override - public InternalFacet buildFacet(String facetName) { - return new InternalStringTermsFacet(facetName, comparatorType, size, Sets.newHashSet(new InternalStringTermsFacet.TermEntry(indexName, count)), 0, count); - } - - class Collector extends FacetExecutor.Collector { - - private int count; - - @Override - public void setNextReader(AtomicReaderContext context) throws IOException { - } - - @Override - public void collect(int doc) throws IOException { - count++; - } - - @Override - public void postCollection() { - IndexNameFacetExecutor.this.count = count; - } - } -} diff --git a/src/test/java/org/elasticsearch/search/aggregations/bucket/StringTermsTests.java b/src/test/java/org/elasticsearch/search/aggregations/bucket/StringTermsTests.java index 5729aeb21816a..74740cfd36cfc 100644 --- a/src/test/java/org/elasticsearch/search/aggregations/bucket/StringTermsTests.java +++ b/src/test/java/org/elasticsearch/search/aggregations/bucket/StringTermsTests.java @@ -22,6 +22,7 @@ import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.index.mapper.internal.IndexFieldMapper; import org.elasticsearch.index.query.FilterBuilders; import org.elasticsearch.search.aggregations.bucket.filter.Filter; import org.elasticsearch.search.aggregations.bucket.histogram.Histogram; @@ -1154,4 +1155,27 @@ public void singleValuedField_OrderedByMultiValueExtendedStatsAsc() throws Excep } } + + @Test + public void indexMetaField() throws Exception { + SearchResponse response = client().prepareSearch("idx", "empty_bucket_idx").setTypes("type") + .addAggregation(terms("terms") + .executionHint(randomExecutionHint()) + .field(IndexFieldMapper.NAME) + ).execute().actionGet(); + + assertSearchResponse(response); + Terms terms = response.getAggregations().get("terms"); + assertThat(terms, notNullValue()); + assertThat(terms.getName(), equalTo("terms")); + assertThat(terms.getBuckets().size(), equalTo(2)); + + int i = 0; + for (Terms.Bucket bucket : terms.getBuckets()) { + assertThat(bucket, notNullValue()); + assertThat(key(bucket), equalTo(i == 0 ? "idx" : "empty_bucket_idx")); + assertThat(bucket.getDocCount(), equalTo(i == 0 ? 5L : 2L)); + i++; + } + } }