mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-17 18:35:25 +00:00
initial commit
This commit is contained in:
parent
7cfdd9ef59
commit
7397007e05
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.common.lucene;
|
||||||
|
|
||||||
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapped to {@link BytesRef} that also caches the hashCode for it.
|
||||||
|
*/
|
||||||
|
public class HashedBytesRef {
|
||||||
|
|
||||||
|
public BytesRef bytes;
|
||||||
|
public int hash;
|
||||||
|
|
||||||
|
public HashedBytesRef() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashedBytesRef(String bytes) {
|
||||||
|
this(new BytesRef(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashedBytesRef(BytesRef bytes) {
|
||||||
|
this(bytes, bytes.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashedBytesRef(BytesRef bytes, int hash) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
this.hash = hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashedBytesRef resetHashCode() {
|
||||||
|
this.hash = bytes.hashCode();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashedBytesRef reset(BytesRef bytes, int hash) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
this.hash = hash;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (other instanceof HashedBytesRef) {
|
||||||
|
return bytes.equals(((HashedBytesRef) other).bytes);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return bytes.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package org.elasticsearch.index.fielddata;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.index.AbstractIndexComponent;
|
||||||
|
import org.elasticsearch.index.Index;
|
||||||
|
import org.elasticsearch.index.settings.IndexSettings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public abstract class AbstractIndexFieldData<FD extends AtomicFieldData> extends AbstractIndexComponent implements IndexFieldData<FD> {
|
||||||
|
|
||||||
|
private final String fieldName;
|
||||||
|
protected final FieldDataType fieldDataType;
|
||||||
|
protected final IndexFieldDataCache cache;
|
||||||
|
|
||||||
|
public AbstractIndexFieldData(Index index, @IndexSettings Settings indexSettings, String fieldName, FieldDataType fieldDataType, IndexFieldDataCache cache) {
|
||||||
|
super(index, indexSettings);
|
||||||
|
this.fieldName = fieldName;
|
||||||
|
this.fieldDataType = fieldDataType;
|
||||||
|
this.cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFieldName() {
|
||||||
|
return this.fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
cache.clear(index, fieldName);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The thread safe {@link org.apache.lucene.index.AtomicReader} level cache of the data.
|
||||||
|
*/
|
||||||
|
public interface AtomicFieldData<Script extends ScriptDocValues> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does *one* of the docs contain multi values?
|
||||||
|
*/
|
||||||
|
boolean isMultiValued();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Are the values ordered? (in ascending manner).
|
||||||
|
*/
|
||||||
|
boolean isValuesOrdered();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of docs in this field data.
|
||||||
|
*/
|
||||||
|
int getNumDocs();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size (in bytes) of memory used by this field data.
|
||||||
|
*/
|
||||||
|
long getMemorySizeInBytes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use a non thread safe (lightweight) view of the values as bytes.
|
||||||
|
*/
|
||||||
|
BytesValues getBytesValues();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use a non thread safe (lightweight) view of the values as bytes.
|
||||||
|
*/
|
||||||
|
HashedBytesValues getHashedBytesValues();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use a non thread safe (lightweight) view of the values as strings.
|
||||||
|
*/
|
||||||
|
StringValues getStringValues();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a "scripting" based values.
|
||||||
|
*/
|
||||||
|
Script getScriptValues();
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface AtomicNumericFieldData<Script extends ScriptDocValues> extends AtomicFieldData<Script> {
|
||||||
|
|
||||||
|
ByteValues getByteValues();
|
||||||
|
|
||||||
|
ShortValues getShortValues();
|
||||||
|
|
||||||
|
IntValues getIntValues();
|
||||||
|
|
||||||
|
LongValues getLongValues();
|
||||||
|
|
||||||
|
FloatValues getFloatValues();
|
||||||
|
|
||||||
|
DoubleValues getDoubleValues();
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface AtomicOrdinalFieldData<Script extends ScriptDocValues> extends AtomicFieldData<Script> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use a non thread safe (lightweight) view of the values as bytes.
|
||||||
|
*/
|
||||||
|
OrdinalsBytesValues getBytesValues();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use a non thread safe (lightweight) view of the values as bytes.
|
||||||
|
*/
|
||||||
|
OrdinalsHashedBytesValues getHashedBytesValues();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use a non thread safe (lightweight) view of the values as strings.
|
||||||
|
*/
|
||||||
|
OrdinalsStringValues getStringValues();
|
||||||
|
}
|
198
src/main/java/org/elasticsearch/index/fielddata/ByteValues.java
Normal file
198
src/main/java/org/elasticsearch/index/fielddata/ByteValues.java
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticSearchIllegalStateException;
|
||||||
|
import org.elasticsearch.index.fielddata.util.ByteArrayRef;
|
||||||
|
import org.elasticsearch.index.fielddata.util.LongArrayRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface ByteValues {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is one of the documents in this field data values is multi valued?
|
||||||
|
*/
|
||||||
|
boolean isMultiValued();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is there a value for this doc?
|
||||||
|
*/
|
||||||
|
boolean hasValue(int docId);
|
||||||
|
|
||||||
|
byte getValue(int docId);
|
||||||
|
|
||||||
|
byte getValueMissing(int docId, byte missingValue);
|
||||||
|
|
||||||
|
ByteArrayRef getValues(int docId);
|
||||||
|
|
||||||
|
Iter getIter(int docId);
|
||||||
|
|
||||||
|
void forEachValueInDoc(int docId, ValueInDocProc proc);
|
||||||
|
|
||||||
|
static interface ValueInDocProc {
|
||||||
|
void onValue(int docId, byte value);
|
||||||
|
|
||||||
|
void onMissing(int docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static interface Iter {
|
||||||
|
|
||||||
|
boolean hasNext();
|
||||||
|
|
||||||
|
byte next();
|
||||||
|
|
||||||
|
static class Empty implements Iter {
|
||||||
|
|
||||||
|
public static final Empty INSTANCE = new Empty();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte next() {
|
||||||
|
throw new ElasticSearchIllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Single implements Iter {
|
||||||
|
|
||||||
|
public byte value;
|
||||||
|
public boolean done;
|
||||||
|
|
||||||
|
public Single reset(byte value) {
|
||||||
|
this.value = value;
|
||||||
|
this.done = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return !done;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte next() {
|
||||||
|
assert !done;
|
||||||
|
done = true;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LongBased implements ByteValues {
|
||||||
|
|
||||||
|
private final LongValues values;
|
||||||
|
|
||||||
|
private final ByteArrayRef arrayScratch = new ByteArrayRef(new byte[1], 1);
|
||||||
|
private final ValueIter iter = new ValueIter();
|
||||||
|
private final Proc proc = new Proc();
|
||||||
|
|
||||||
|
public LongBased(LongValues values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return values.isMultiValued();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return values.hasValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getValue(int docId) {
|
||||||
|
return (byte) values.getValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getValueMissing(int docId, byte missingValue) {
|
||||||
|
return (byte) values.getValueMissing(docId, missingValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteArrayRef getValues(int docId) {
|
||||||
|
LongArrayRef arrayRef = values.getValues(docId);
|
||||||
|
int size = arrayRef.size();
|
||||||
|
if (size == 0) {
|
||||||
|
return ByteArrayRef.EMPTY;
|
||||||
|
}
|
||||||
|
arrayScratch.reset(size);
|
||||||
|
for (int i = arrayRef.start; i < arrayRef.end; i++) {
|
||||||
|
arrayScratch.values[arrayScratch.end++] = (byte) arrayRef.values[i];
|
||||||
|
}
|
||||||
|
return arrayScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return iter.reset(values.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
values.forEachValueInDoc(docId, this.proc.reset(proc));
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ValueIter implements Iter {
|
||||||
|
|
||||||
|
private LongValues.Iter iter;
|
||||||
|
|
||||||
|
public ValueIter reset(LongValues.Iter iter) {
|
||||||
|
this.iter = iter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return iter.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte next() {
|
||||||
|
return (byte) iter.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Proc implements LongValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private ValueInDocProc proc;
|
||||||
|
|
||||||
|
public Proc reset(ValueInDocProc proc) {
|
||||||
|
this.proc = proc;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, long value) {
|
||||||
|
proc.onValue(docId, (byte) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
305
src/main/java/org/elasticsearch/index/fielddata/BytesValues.java
Normal file
305
src/main/java/org/elasticsearch/index/fielddata/BytesValues.java
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.elasticsearch.ElasticSearchIllegalStateException;
|
||||||
|
import org.elasticsearch.index.fielddata.util.BytesRefArrayRef;
|
||||||
|
import org.elasticsearch.index.fielddata.util.StringArrayRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface BytesValues {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is there a value for this doc?
|
||||||
|
*/
|
||||||
|
boolean hasValue(int docId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is one of the documents in this field data values is multi valued?
|
||||||
|
*/
|
||||||
|
boolean isMultiValued();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bytes value for a docId. Note, the content of it might be shared across invocation.
|
||||||
|
*/
|
||||||
|
BytesRef getValue(int docId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the bytes value for the docId, with the provided "ret" which will be filled with the
|
||||||
|
* result which will also be returned. If there is no value for this docId, the length will be 0.
|
||||||
|
* Note, the bytes are not "safe".
|
||||||
|
*/
|
||||||
|
BytesRef getValueScratch(int docId, BytesRef ret);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bytes value for a docId. The content is guaranteed not to be shared.
|
||||||
|
*/
|
||||||
|
BytesRef getValueSafe(int docId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array wrapping all the bytes values for a doc. The content is guaranteed not to be shared.
|
||||||
|
*/
|
||||||
|
BytesRefArrayRef getValues(int docId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bytes value iterator for a docId. Note, the content of it might be shared across invocation.
|
||||||
|
*/
|
||||||
|
Iter getIter(int docId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bytes value iterator for a docId. The content is guaranteed not to be shared.
|
||||||
|
*/
|
||||||
|
Iter getIterSafe(int docId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go over all the possible values in their BytesRef format for a specific doc.
|
||||||
|
*/
|
||||||
|
void forEachValueInDoc(int docId, ValueInDocProc proc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go over all the possible values in their BytesRef format for a specific doc.
|
||||||
|
*/
|
||||||
|
void forEachSafeValueInDoc(int docId, ValueInDocProc proc);
|
||||||
|
|
||||||
|
public static interface ValueInDocProc {
|
||||||
|
void onValue(int docId, BytesRef value);
|
||||||
|
|
||||||
|
void onMissing(int docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static interface Iter {
|
||||||
|
|
||||||
|
boolean hasNext();
|
||||||
|
|
||||||
|
BytesRef next();
|
||||||
|
|
||||||
|
static class Empty implements Iter {
|
||||||
|
|
||||||
|
public static final Empty INSTANCE = new Empty();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef next() {
|
||||||
|
throw new ElasticSearchIllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Single implements Iter {
|
||||||
|
|
||||||
|
public BytesRef value;
|
||||||
|
public boolean done;
|
||||||
|
|
||||||
|
public Single reset(BytesRef value) {
|
||||||
|
this.value = value;
|
||||||
|
this.done = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return !done;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef next() {
|
||||||
|
assert !done;
|
||||||
|
done = true;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class StringBased implements BytesValues {
|
||||||
|
|
||||||
|
private final StringValues values;
|
||||||
|
|
||||||
|
protected final BytesRef scratch = new BytesRef();
|
||||||
|
private final BytesRefArrayRef arrayScratch = new BytesRefArrayRef(new BytesRef[1], 1);
|
||||||
|
private final ValueIter valueIter = new ValueIter();
|
||||||
|
private final SafeValueIter safeValueIter = new SafeValueIter();
|
||||||
|
private final Proc proc = new Proc();
|
||||||
|
private final SafeProc safeProc = new SafeProc();
|
||||||
|
|
||||||
|
public StringBased(StringValues values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return values.hasValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return values.isMultiValued();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef getValue(int docId) {
|
||||||
|
String value = values.getValue(docId);
|
||||||
|
if (value == null) return null;
|
||||||
|
scratch.copyChars(value);
|
||||||
|
return scratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef getValueScratch(int docId, BytesRef ret) {
|
||||||
|
String value = values.getValue(docId);
|
||||||
|
if (value == null) {
|
||||||
|
ret.length = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret.copyChars(value);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef getValueSafe(int docId) {
|
||||||
|
String value = values.getValue(docId);
|
||||||
|
if (value == null) return null;
|
||||||
|
return new BytesRef(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRefArrayRef getValues(int docId) {
|
||||||
|
StringArrayRef arrayRef = values.getValues(docId);
|
||||||
|
int size = arrayRef.size();
|
||||||
|
if (size == 0) {
|
||||||
|
return BytesRefArrayRef.EMPTY;
|
||||||
|
}
|
||||||
|
arrayScratch.reset(size);
|
||||||
|
for (int i = arrayRef.start; i < arrayRef.end; i++) {
|
||||||
|
String value = arrayRef.values[i];
|
||||||
|
arrayScratch.values[arrayScratch.end++] = value == null ? null : new BytesRef(value);
|
||||||
|
}
|
||||||
|
return arrayScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return valueIter.reset(values.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIterSafe(int docId) {
|
||||||
|
return safeValueIter.reset(values.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
values.forEachValueInDoc(docId, this.proc.reset(proc));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachSafeValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
values.forEachValueInDoc(docId, this.safeProc.reset(proc));
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ValueIter implements Iter {
|
||||||
|
|
||||||
|
private final BytesRef scratch = new BytesRef();
|
||||||
|
private StringValues.Iter iter;
|
||||||
|
|
||||||
|
public ValueIter reset(StringValues.Iter iter) {
|
||||||
|
this.iter = iter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return iter.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef next() {
|
||||||
|
scratch.copyChars(iter.next());
|
||||||
|
return scratch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SafeValueIter implements Iter {
|
||||||
|
|
||||||
|
private StringValues.Iter iter;
|
||||||
|
|
||||||
|
public SafeValueIter reset(StringValues.Iter iter) {
|
||||||
|
this.iter = iter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return iter.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef next() {
|
||||||
|
return new BytesRef(iter.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Proc implements StringValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private final BytesRef scratch = new BytesRef();
|
||||||
|
private BytesValues.ValueInDocProc proc;
|
||||||
|
|
||||||
|
public Proc reset(BytesValues.ValueInDocProc proc) {
|
||||||
|
this.proc = proc;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, String value) {
|
||||||
|
scratch.copyChars(value);
|
||||||
|
proc.onValue(docId, scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SafeProc implements StringValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private BytesValues.ValueInDocProc proc;
|
||||||
|
|
||||||
|
public SafeProc reset(BytesValues.ValueInDocProc proc) {
|
||||||
|
this.proc = proc;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, String value) {
|
||||||
|
proc.onValue(docId, new BytesRef(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticSearchIllegalStateException;
|
||||||
|
import org.elasticsearch.index.fielddata.util.DoubleArrayRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface DoubleValues {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is one of the documents in this field data values is multi valued?
|
||||||
|
*/
|
||||||
|
boolean isMultiValued();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is there a value for this doc?
|
||||||
|
*/
|
||||||
|
boolean hasValue(int docId);
|
||||||
|
|
||||||
|
double getValue(int docId);
|
||||||
|
|
||||||
|
double getValueMissing(int docId, double missingValue);
|
||||||
|
|
||||||
|
DoubleArrayRef getValues(int docId);
|
||||||
|
|
||||||
|
Iter getIter(int docId);
|
||||||
|
|
||||||
|
void forEachValueInDoc(int docId, ValueInDocProc proc);
|
||||||
|
|
||||||
|
static interface ValueInDocProc {
|
||||||
|
void onValue(int docId, double value);
|
||||||
|
|
||||||
|
void onMissing(int docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static interface Iter {
|
||||||
|
|
||||||
|
boolean hasNext();
|
||||||
|
|
||||||
|
double next();
|
||||||
|
|
||||||
|
static class Empty implements Iter {
|
||||||
|
|
||||||
|
public static final Empty INSTANCE = new Empty();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double next() {
|
||||||
|
throw new ElasticSearchIllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Single implements Iter {
|
||||||
|
|
||||||
|
public double value;
|
||||||
|
public boolean done;
|
||||||
|
|
||||||
|
public Single reset(double value) {
|
||||||
|
this.value = value;
|
||||||
|
this.done = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return !done;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double next() {
|
||||||
|
assert !done;
|
||||||
|
done = true;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import org.elasticsearch.common.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class FieldDataType {
|
||||||
|
|
||||||
|
private final String type;
|
||||||
|
@Nullable
|
||||||
|
private final String format;
|
||||||
|
private final ImmutableMap<String, String> options;
|
||||||
|
|
||||||
|
public FieldDataType(String type) {
|
||||||
|
this(type, null, ImmutableMap.<String, String>of());
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldDataType(String type, @Nullable String format, ImmutableMap<String, String> options) {
|
||||||
|
this.type = type;
|
||||||
|
this.format = format;
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getFormat() {
|
||||||
|
return this.format;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmutableMap<String, String> getOptions() {
|
||||||
|
return this.options;
|
||||||
|
}
|
||||||
|
}
|
198
src/main/java/org/elasticsearch/index/fielddata/FloatValues.java
Normal file
198
src/main/java/org/elasticsearch/index/fielddata/FloatValues.java
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticSearchIllegalStateException;
|
||||||
|
import org.elasticsearch.index.fielddata.util.DoubleArrayRef;
|
||||||
|
import org.elasticsearch.index.fielddata.util.FloatArrayRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface FloatValues {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is one of the documents in this field data values is multi valued?
|
||||||
|
*/
|
||||||
|
boolean isMultiValued();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is there a value for this doc?
|
||||||
|
*/
|
||||||
|
boolean hasValue(int docId);
|
||||||
|
|
||||||
|
float getValue(int docId);
|
||||||
|
|
||||||
|
float getValueMissing(int docId, float missingValue);
|
||||||
|
|
||||||
|
FloatArrayRef getValues(int docId);
|
||||||
|
|
||||||
|
Iter getIter(int docId);
|
||||||
|
|
||||||
|
void forEachValueInDoc(int docId, ValueInDocProc proc);
|
||||||
|
|
||||||
|
static interface ValueInDocProc {
|
||||||
|
void onValue(int docId, float value);
|
||||||
|
|
||||||
|
void onMissing(int docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static interface Iter {
|
||||||
|
|
||||||
|
boolean hasNext();
|
||||||
|
|
||||||
|
float next();
|
||||||
|
|
||||||
|
static class Empty implements Iter {
|
||||||
|
|
||||||
|
public static final Empty INSTANCE = new Empty();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float next() {
|
||||||
|
throw new ElasticSearchIllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Single implements Iter {
|
||||||
|
|
||||||
|
public float value;
|
||||||
|
public boolean done;
|
||||||
|
|
||||||
|
public Single reset(float value) {
|
||||||
|
this.value = value;
|
||||||
|
this.done = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return !done;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float next() {
|
||||||
|
assert !done;
|
||||||
|
done = true;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DoubleBased implements FloatValues {
|
||||||
|
|
||||||
|
private final DoubleValues values;
|
||||||
|
|
||||||
|
private final FloatArrayRef arrayScratch = new FloatArrayRef(new float[1], 1);
|
||||||
|
private final ValueIter iter = new ValueIter();
|
||||||
|
private final Proc proc = new Proc();
|
||||||
|
|
||||||
|
public DoubleBased(DoubleValues values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return values.isMultiValued();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return values.hasValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getValue(int docId) {
|
||||||
|
return (float) values.getValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getValueMissing(int docId, float missingValue) {
|
||||||
|
return (float) values.getValueMissing(docId, missingValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FloatArrayRef getValues(int docId) {
|
||||||
|
DoubleArrayRef arrayRef = values.getValues(docId);
|
||||||
|
int size = arrayRef.size();
|
||||||
|
if (size == 0) {
|
||||||
|
return FloatArrayRef.EMPTY;
|
||||||
|
}
|
||||||
|
arrayScratch.reset(size);
|
||||||
|
for (int i = arrayRef.start; i < arrayRef.end; i++) {
|
||||||
|
arrayScratch.values[arrayScratch.end++] = (float) arrayRef.values[i];
|
||||||
|
}
|
||||||
|
return arrayScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return iter.reset(values.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
values.forEachValueInDoc(docId, this.proc.reset(proc));
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ValueIter implements Iter {
|
||||||
|
|
||||||
|
private DoubleValues.Iter iter;
|
||||||
|
|
||||||
|
public ValueIter reset(DoubleValues.Iter iter) {
|
||||||
|
this.iter = iter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return iter.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float next() {
|
||||||
|
return (float) iter.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Proc implements DoubleValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private ValueInDocProc proc;
|
||||||
|
|
||||||
|
public Proc reset(ValueInDocProc proc) {
|
||||||
|
this.proc = proc;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, double value) {
|
||||||
|
proc.onValue(docId, (float) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,411 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.elasticsearch.ElasticSearchIllegalStateException;
|
||||||
|
import org.elasticsearch.common.lucene.HashedBytesRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface HashedBytesValues {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is one of the documents in this field data values is multi valued?
|
||||||
|
*/
|
||||||
|
boolean isMultiValued();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is there a value for this doc?
|
||||||
|
*/
|
||||||
|
boolean hasValue(int docId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bytes value for a docId. Note, the content of it might be shared across invocation.
|
||||||
|
*/
|
||||||
|
HashedBytesRef getValue(int docId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bytes value for a docId. The content is guaranteed not to be shared.
|
||||||
|
*/
|
||||||
|
HashedBytesRef getValueSafe(int docId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bytes value iterator for a docId. Note, the content of it might be shared across invocation.
|
||||||
|
*/
|
||||||
|
Iter getIter(int docId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bytes value iterator for a docId. The content is guaranteed not to be shared.
|
||||||
|
*/
|
||||||
|
Iter getIterSafe(int docId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go over all the possible values in their BytesRef format for a specific doc.
|
||||||
|
*/
|
||||||
|
void forEachValueInDoc(int docId, ValueInDocProc proc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go over all the possible values in their BytesRef format for a specific doc.
|
||||||
|
*/
|
||||||
|
void forEachSafeValueInDoc(int docId, ValueInDocProc proc);
|
||||||
|
|
||||||
|
public static interface ValueInDocProc {
|
||||||
|
void onValue(int docId, HashedBytesRef value);
|
||||||
|
|
||||||
|
void onMissing(int docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static interface Iter {
|
||||||
|
|
||||||
|
boolean hasNext();
|
||||||
|
|
||||||
|
HashedBytesRef next();
|
||||||
|
|
||||||
|
static class Empty implements Iter {
|
||||||
|
|
||||||
|
public static final Empty INSTANCE = new Empty();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef next() {
|
||||||
|
throw new ElasticSearchIllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Single implements Iter {
|
||||||
|
|
||||||
|
public HashedBytesRef value;
|
||||||
|
public boolean done;
|
||||||
|
|
||||||
|
public Single reset(HashedBytesRef value) {
|
||||||
|
this.value = value;
|
||||||
|
this.done = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return !done;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef next() {
|
||||||
|
assert !done;
|
||||||
|
done = true;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link BytesValues} based implementation.
|
||||||
|
*/
|
||||||
|
static class BytesBased implements HashedBytesValues {
|
||||||
|
|
||||||
|
private final BytesValues values;
|
||||||
|
|
||||||
|
protected final HashedBytesRef scratch = new HashedBytesRef(new BytesRef());
|
||||||
|
private final ValueIter valueIter = new ValueIter();
|
||||||
|
private final SafeValueIter safeValueIter = new SafeValueIter();
|
||||||
|
private final Proc proc = new Proc();
|
||||||
|
private final SafeProc safeProc = new SafeProc();
|
||||||
|
|
||||||
|
public BytesBased(BytesValues values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return values.isMultiValued();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return values.hasValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef getValue(int docId) {
|
||||||
|
BytesRef value = values.getValue(docId);
|
||||||
|
if (value == null) return null;
|
||||||
|
scratch.bytes = value;
|
||||||
|
return scratch.resetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef getValueSafe(int docId) {
|
||||||
|
return new HashedBytesRef(values.getValueSafe(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return valueIter.reset(values.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIterSafe(int docId) {
|
||||||
|
return safeValueIter.reset(values.getIterSafe(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, final ValueInDocProc proc) {
|
||||||
|
values.forEachValueInDoc(docId, this.proc.reset(proc));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachSafeValueInDoc(int docId, final ValueInDocProc proc) {
|
||||||
|
values.forEachValueInDoc(docId, this.safeProc.reset(proc));
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ValueIter implements Iter {
|
||||||
|
|
||||||
|
private final HashedBytesRef scratch = new HashedBytesRef(new BytesRef());
|
||||||
|
private BytesValues.Iter iter;
|
||||||
|
|
||||||
|
public ValueIter reset(BytesValues.Iter iter) {
|
||||||
|
this.iter = iter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return iter.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef next() {
|
||||||
|
scratch.bytes = iter.next();
|
||||||
|
return scratch.resetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SafeValueIter implements Iter {
|
||||||
|
|
||||||
|
private BytesValues.Iter iter;
|
||||||
|
|
||||||
|
public SafeValueIter reset(BytesValues.Iter iter) {
|
||||||
|
this.iter = iter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return iter.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef next() {
|
||||||
|
return new HashedBytesRef(iter.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Proc implements BytesValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private final HashedBytesRef scratch = new HashedBytesRef();
|
||||||
|
private ValueInDocProc proc;
|
||||||
|
|
||||||
|
public Proc reset(ValueInDocProc proc) {
|
||||||
|
this.proc = proc;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, BytesRef value) {
|
||||||
|
scratch.bytes = value;
|
||||||
|
proc.onValue(docId, scratch.resetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SafeProc implements BytesValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private ValueInDocProc proc;
|
||||||
|
|
||||||
|
public SafeProc reset(ValueInDocProc proc) {
|
||||||
|
this.proc = proc;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, BytesRef value) {
|
||||||
|
proc.onValue(docId, new HashedBytesRef(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class StringBased implements HashedBytesValues {
|
||||||
|
|
||||||
|
private final StringValues values;
|
||||||
|
|
||||||
|
protected final HashedBytesRef scratch = new HashedBytesRef(new BytesRef());
|
||||||
|
private final ValueIter valueIter = new ValueIter();
|
||||||
|
private final SafeValueIter safeValueIter = new SafeValueIter();
|
||||||
|
private final Proc proc = new Proc();
|
||||||
|
private final SafeProc safeProc = new SafeProc();
|
||||||
|
|
||||||
|
public StringBased(StringValues values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return values.isMultiValued();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return values.hasValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef getValue(int docId) {
|
||||||
|
String value = values.getValue(docId);
|
||||||
|
if (value == null) return null;
|
||||||
|
scratch.bytes.copyChars(value);
|
||||||
|
return scratch.resetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef getValueSafe(int docId) {
|
||||||
|
String value = values.getValue(docId);
|
||||||
|
if (value == null) return null;
|
||||||
|
return new HashedBytesRef(new BytesRef(values.getValue(docId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return valueIter.reset(values.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIterSafe(int docId) {
|
||||||
|
return safeValueIter.reset(values.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, final ValueInDocProc proc) {
|
||||||
|
values.forEachValueInDoc(docId, this.proc.reset(proc));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachSafeValueInDoc(int docId, final ValueInDocProc proc) {
|
||||||
|
values.forEachValueInDoc(docId, this.safeProc.reset(proc));
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ValueIter implements Iter {
|
||||||
|
|
||||||
|
private final HashedBytesRef scratch = new HashedBytesRef(new BytesRef());
|
||||||
|
private StringValues.Iter iter;
|
||||||
|
|
||||||
|
public ValueIter reset(StringValues.Iter iter) {
|
||||||
|
this.iter = iter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return iter.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef next() {
|
||||||
|
scratch.bytes.copyChars(iter.next());
|
||||||
|
return scratch.resetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SafeValueIter implements Iter {
|
||||||
|
|
||||||
|
private StringValues.Iter iter;
|
||||||
|
|
||||||
|
public SafeValueIter reset(StringValues.Iter iter) {
|
||||||
|
this.iter = iter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return iter.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef next() {
|
||||||
|
return new HashedBytesRef(new BytesRef(iter.next()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Proc implements StringValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private final HashedBytesRef scratch = new HashedBytesRef(new BytesRef());
|
||||||
|
private ValueInDocProc proc;
|
||||||
|
|
||||||
|
public Proc reset(ValueInDocProc proc) {
|
||||||
|
this.proc = proc;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, String value) {
|
||||||
|
scratch.bytes.copyChars(value);
|
||||||
|
proc.onValue(docId, scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SafeProc implements StringValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private ValueInDocProc proc;
|
||||||
|
|
||||||
|
public SafeProc reset(ValueInDocProc proc) {
|
||||||
|
this.proc = proc;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, String value) {
|
||||||
|
proc.onValue(docId, new HashedBytesRef(new BytesRef(value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import org.apache.lucene.index.AtomicReaderContext;
|
||||||
|
import org.apache.lucene.search.FieldComparatorSource;
|
||||||
|
import org.apache.lucene.search.SortField;
|
||||||
|
import org.elasticsearch.common.Nullable;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.index.Index;
|
||||||
|
import org.elasticsearch.index.IndexComponent;
|
||||||
|
import org.elasticsearch.index.settings.IndexSettings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface IndexFieldData<FD extends AtomicFieldData> extends IndexComponent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The field name.
|
||||||
|
*/
|
||||||
|
String getFieldName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Are the values ordered? (in ascending manner).
|
||||||
|
*/
|
||||||
|
boolean valuesOrdered();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the atomic field data for the reader, possibly cached.
|
||||||
|
*/
|
||||||
|
FD load(AtomicReaderContext context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads directly the atomic field data for the reader, ignoring any caching involved.
|
||||||
|
*/
|
||||||
|
FD loadDirect(AtomicReaderContext context) throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comparator used for sorting.
|
||||||
|
*/
|
||||||
|
XFieldComparatorSource comparatorSource(@Nullable Object missingValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears any resources associated with this field data.
|
||||||
|
*/
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
// we need this extended source we we have custom comparators to reuse our field data
|
||||||
|
// in this case, we need to reduce type that will be used when search results are reduced
|
||||||
|
// on another node (we don't have the custom source them...)
|
||||||
|
public abstract class XFieldComparatorSource extends FieldComparatorSource {
|
||||||
|
|
||||||
|
public abstract SortField.Type reducedType();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Builder {
|
||||||
|
|
||||||
|
IndexFieldData build(Index index, @IndexSettings Settings indexSettings, String fieldName, FieldDataType type, IndexFieldDataCache cache);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import com.google.common.cache.Cache;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import org.apache.lucene.index.AtomicReaderContext;
|
||||||
|
import org.apache.lucene.index.SegmentReader;
|
||||||
|
import org.elasticsearch.index.Index;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple field data cache abstraction.
|
||||||
|
*/
|
||||||
|
public interface IndexFieldDataCache {
|
||||||
|
|
||||||
|
<FD extends AtomicFieldData, IFD extends IndexFieldData<FD>> FD load(AtomicReaderContext context, IFD indexFieldData) throws Exception;
|
||||||
|
|
||||||
|
void clear(Index index);
|
||||||
|
|
||||||
|
void clear(Index index, String fieldName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The resident field data cache is a *per field* cache that keeps all the values in memory.
|
||||||
|
*/
|
||||||
|
static abstract class FieldBased implements IndexFieldDataCache, SegmentReader.CoreClosedListener {
|
||||||
|
private final Cache<Object, AtomicFieldData> cache;
|
||||||
|
|
||||||
|
protected FieldBased(Cache<Object, AtomicFieldData> cache) {
|
||||||
|
this.cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose(SegmentReader owner) {
|
||||||
|
cache.invalidate(owner.getCoreCacheKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <FD extends AtomicFieldData, IFD extends IndexFieldData<FD>> FD load(final AtomicReaderContext context, final IFD indexFieldData) throws Exception {
|
||||||
|
//noinspection unchecked
|
||||||
|
return (FD) cache.get(context.reader().getCoreCacheKey(), new Callable<AtomicFieldData>() {
|
||||||
|
@Override
|
||||||
|
public AtomicFieldData call() throws Exception {
|
||||||
|
return indexFieldData.loadDirect(context);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear(Index index) {
|
||||||
|
cache.invalidateAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear(Index index, String fieldName) {
|
||||||
|
cache.invalidateAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Resident extends FieldBased {
|
||||||
|
|
||||||
|
public Resident() {
|
||||||
|
super(CacheBuilder.newBuilder().<Object, AtomicFieldData>build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Soft extends FieldBased {
|
||||||
|
|
||||||
|
public Soft() {
|
||||||
|
super(CacheBuilder.newBuilder().softValues().<Object, AtomicFieldData>build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
||||||
|
import org.elasticsearch.common.collect.MapBuilder;
|
||||||
|
import org.elasticsearch.common.collect.Tuple;
|
||||||
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
|
||||||
|
import org.elasticsearch.index.AbstractIndexComponent;
|
||||||
|
import org.elasticsearch.index.Index;
|
||||||
|
import org.elasticsearch.index.fielddata.plain.ConcreteBytesRefIndexFieldData;
|
||||||
|
import org.elasticsearch.index.fielddata.plain.DoubleArrayIndexFieldData;
|
||||||
|
import org.elasticsearch.index.settings.IndexSettings;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class IndexFieldDataService extends AbstractIndexComponent {
|
||||||
|
|
||||||
|
private final static ImmutableMap<String, IndexFieldData.Builder> buildersByType;
|
||||||
|
private final static ImmutableMap<Tuple<String, String>, IndexFieldData.Builder> buildersByTypeAndFormat;
|
||||||
|
|
||||||
|
static {
|
||||||
|
buildersByType = MapBuilder.<String, IndexFieldData.Builder>newMapBuilder()
|
||||||
|
.put("string", new ConcreteBytesRefIndexFieldData.Builder())
|
||||||
|
.put("double", new DoubleArrayIndexFieldData.Builder())
|
||||||
|
.immutableMap();
|
||||||
|
|
||||||
|
buildersByTypeAndFormat = MapBuilder.<Tuple<String, String>, IndexFieldData.Builder>newMapBuilder().
|
||||||
|
put(Tuple.tuple("string", "concrete_bytes"), new ConcreteBytesRefIndexFieldData.Builder())
|
||||||
|
.put(Tuple.tuple("double", "array"), new DoubleArrayIndexFieldData.Builder())
|
||||||
|
.immutableMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ConcurrentMap<String, IndexFieldData> loadedFieldData = ConcurrentCollections.newConcurrentMap();
|
||||||
|
|
||||||
|
public IndexFieldDataService(Index index) {
|
||||||
|
this(index, ImmutableSettings.Builder.EMPTY_SETTINGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public IndexFieldDataService(Index index, @IndexSettings Settings indexSettings) {
|
||||||
|
super(index, indexSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
synchronized (loadedFieldData) {
|
||||||
|
for (IndexFieldData fieldData : loadedFieldData.values()) {
|
||||||
|
fieldData.clear();
|
||||||
|
}
|
||||||
|
loadedFieldData.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearField(String fieldName) {
|
||||||
|
synchronized (loadedFieldData) {
|
||||||
|
IndexFieldData fieldData = loadedFieldData.remove(fieldName);
|
||||||
|
if (fieldData != null) {
|
||||||
|
fieldData.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <IFD extends IndexFieldData> IFD getForField(String fieldName, FieldDataType type) {
|
||||||
|
IndexFieldData fieldData = loadedFieldData.get(type.getType());
|
||||||
|
if (fieldData == null) {
|
||||||
|
synchronized (loadedFieldData) {
|
||||||
|
fieldData = loadedFieldData.get(type.getType());
|
||||||
|
if (fieldData == null) {
|
||||||
|
IndexFieldData.Builder builder = null;
|
||||||
|
if (type.getFormat() != null) {
|
||||||
|
builder = buildersByTypeAndFormat.get(Tuple.tuple(type.getType(), type.getFormat()));
|
||||||
|
}
|
||||||
|
if (builder == null) {
|
||||||
|
builder = buildersByType.get(type.getType());
|
||||||
|
}
|
||||||
|
if (builder == null) {
|
||||||
|
throw new ElasticSearchIllegalArgumentException("failed to find field data builder for field " + fieldName + ", and type " + type);
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexFieldDataCache cache;
|
||||||
|
if (type.getOptions().containsKey("cache")) {
|
||||||
|
String cacheType = type.getOptions().get("cache");
|
||||||
|
if ("resident".equals(cacheType)) {
|
||||||
|
cache = new IndexFieldDataCache.Resident();
|
||||||
|
} else if ("soft".equals(cacheType)) {
|
||||||
|
cache = new IndexFieldDataCache.Soft();
|
||||||
|
} else {
|
||||||
|
throw new ElasticSearchIllegalArgumentException("cache type not supported [" + cacheType + "] for field [" + fieldName + "]");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cache = new IndexFieldDataCache.Resident();
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldData = builder.build(index, indexSettings, fieldName, type, cache);
|
||||||
|
loadedFieldData.put(fieldName, fieldData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (IFD) fieldData;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import org.apache.lucene.index.AtomicReaderContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface IndexNumericFieldData<FD extends AtomicNumericFieldData> extends IndexFieldData<FD> {
|
||||||
|
|
||||||
|
static enum NumericType {
|
||||||
|
BYTE,
|
||||||
|
SHORT,
|
||||||
|
INT,
|
||||||
|
LONG,
|
||||||
|
FLOAT,
|
||||||
|
DOUBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
NumericType getNumericType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the atomic field data for the reader, possibly cached.
|
||||||
|
*/
|
||||||
|
FD load(AtomicReaderContext context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads directly the atomic field data for the reader, ignoring any caching involved.
|
||||||
|
*/
|
||||||
|
FD loadDirect(AtomicReaderContext context) throws Exception;
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import org.apache.lucene.index.AtomicReaderContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface IndexOrdinalFieldData<FD extends AtomicOrdinalFieldData> extends IndexFieldData<FD> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the atomic field data for the reader, possibly cached.
|
||||||
|
*/
|
||||||
|
FD load(AtomicReaderContext context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads directly the atomic field data for the reader, ignoring any caching involved.
|
||||||
|
*/
|
||||||
|
FD loadDirect(AtomicReaderContext context) throws Exception;
|
||||||
|
}
|
198
src/main/java/org/elasticsearch/index/fielddata/IntValues.java
Normal file
198
src/main/java/org/elasticsearch/index/fielddata/IntValues.java
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticSearchIllegalStateException;
|
||||||
|
import org.elasticsearch.index.fielddata.util.IntArrayRef;
|
||||||
|
import org.elasticsearch.index.fielddata.util.LongArrayRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface IntValues {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is one of the documents in this field data values is multi valued?
|
||||||
|
*/
|
||||||
|
boolean isMultiValued();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is there a value for this doc?
|
||||||
|
*/
|
||||||
|
boolean hasValue(int docId);
|
||||||
|
|
||||||
|
int getValue(int docId);
|
||||||
|
|
||||||
|
int getValueMissing(int docId, int missingValue);
|
||||||
|
|
||||||
|
IntArrayRef getValues(int docId);
|
||||||
|
|
||||||
|
Iter getIter(int docId);
|
||||||
|
|
||||||
|
void forEachValueInDoc(int docId, ValueInDocProc proc);
|
||||||
|
|
||||||
|
static interface ValueInDocProc {
|
||||||
|
void onValue(int docId, int value);
|
||||||
|
|
||||||
|
void onMissing(int docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static interface Iter {
|
||||||
|
|
||||||
|
boolean hasNext();
|
||||||
|
|
||||||
|
int next();
|
||||||
|
|
||||||
|
static class Empty implements Iter {
|
||||||
|
|
||||||
|
public static final Empty INSTANCE = new Empty();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int next() {
|
||||||
|
throw new ElasticSearchIllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Single implements Iter {
|
||||||
|
|
||||||
|
public int value;
|
||||||
|
public boolean done;
|
||||||
|
|
||||||
|
public Single reset(int value) {
|
||||||
|
this.value = value;
|
||||||
|
this.done = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return !done;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int next() {
|
||||||
|
assert !done;
|
||||||
|
done = true;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LongBased implements IntValues {
|
||||||
|
|
||||||
|
private final LongValues values;
|
||||||
|
|
||||||
|
private final IntArrayRef arrayScratch = new IntArrayRef(new int[1], 1);
|
||||||
|
private final ValueIter iter = new ValueIter();
|
||||||
|
private final Proc proc = new Proc();
|
||||||
|
|
||||||
|
public LongBased(LongValues values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return values.isMultiValued();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return values.hasValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getValue(int docId) {
|
||||||
|
return (int) values.getValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getValueMissing(int docId, int missingValue) {
|
||||||
|
return (int) values.getValueMissing(docId, missingValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntArrayRef getValues(int docId) {
|
||||||
|
LongArrayRef arrayRef = values.getValues(docId);
|
||||||
|
int size = arrayRef.size();
|
||||||
|
if (size == 0) {
|
||||||
|
return IntArrayRef.EMPTY;
|
||||||
|
}
|
||||||
|
arrayScratch.reset(size);
|
||||||
|
for (int i = arrayRef.start; i < arrayRef.end; i++) {
|
||||||
|
arrayScratch.values[arrayScratch.end++] = (int) arrayRef.values[i];
|
||||||
|
}
|
||||||
|
return arrayScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return iter.reset(values.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
values.forEachValueInDoc(docId, this.proc.reset(proc));
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ValueIter implements Iter {
|
||||||
|
|
||||||
|
private LongValues.Iter iter;
|
||||||
|
|
||||||
|
public ValueIter reset(LongValues.Iter iter) {
|
||||||
|
this.iter = iter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return iter.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int next() {
|
||||||
|
return (int) iter.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Proc implements LongValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private ValueInDocProc proc;
|
||||||
|
|
||||||
|
public Proc reset(ValueInDocProc proc) {
|
||||||
|
this.proc = proc;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, long value) {
|
||||||
|
proc.onValue(docId, (int) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
100
src/main/java/org/elasticsearch/index/fielddata/LongValues.java
Normal file
100
src/main/java/org/elasticsearch/index/fielddata/LongValues.java
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticSearchIllegalStateException;
|
||||||
|
import org.elasticsearch.index.fielddata.util.LongArrayRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface LongValues {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is one of the documents in this field data values is multi valued?
|
||||||
|
*/
|
||||||
|
boolean isMultiValued();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is there a value for this doc?
|
||||||
|
*/
|
||||||
|
boolean hasValue(int docId);
|
||||||
|
|
||||||
|
long getValue(int docId);
|
||||||
|
|
||||||
|
long getValueMissing(int docId, long missingValue);
|
||||||
|
|
||||||
|
LongArrayRef getValues(int docId);
|
||||||
|
|
||||||
|
Iter getIter(int docId);
|
||||||
|
|
||||||
|
void forEachValueInDoc(int docId, ValueInDocProc proc);
|
||||||
|
|
||||||
|
static interface ValueInDocProc {
|
||||||
|
void onValue(int docId, long value);
|
||||||
|
|
||||||
|
void onMissing(int docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static interface Iter {
|
||||||
|
|
||||||
|
boolean hasNext();
|
||||||
|
|
||||||
|
long next();
|
||||||
|
|
||||||
|
static class Empty implements Iter {
|
||||||
|
|
||||||
|
public static final Empty INSTANCE = new Empty();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long next() {
|
||||||
|
throw new ElasticSearchIllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Single implements Iter {
|
||||||
|
|
||||||
|
public long value;
|
||||||
|
public boolean done;
|
||||||
|
|
||||||
|
public Single reset(long value) {
|
||||||
|
this.value = value;
|
||||||
|
this.done = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return !done;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long next() {
|
||||||
|
assert !done;
|
||||||
|
done = true;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface OrdinalsBytesValues extends BytesValues {
|
||||||
|
|
||||||
|
Ordinals.Docs ordinals();
|
||||||
|
|
||||||
|
BytesRef getValueByOrd(int ord);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the bytes value for the docId, with the provided "ret" which will be filled with the
|
||||||
|
* result which will also be returned. If there is no value for this docId, the length will be 0.
|
||||||
|
* Note, the bytes are not "safe".
|
||||||
|
*/
|
||||||
|
BytesRef getValueScratchByOrd(int ord, BytesRef ret);
|
||||||
|
|
||||||
|
BytesRef getSafeValueByOrd(int ord);
|
||||||
|
|
||||||
|
public static class StringBased extends BytesValues.StringBased implements OrdinalsBytesValues {
|
||||||
|
|
||||||
|
private final OrdinalsStringValues values;
|
||||||
|
|
||||||
|
public StringBased(OrdinalsStringValues values) {
|
||||||
|
super(values);
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Ordinals.Docs ordinals() {
|
||||||
|
return values.ordinals();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef getValueByOrd(int ord) {
|
||||||
|
scratch.copyChars(values.getValueByOrd(ord));
|
||||||
|
return scratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef getValueScratchByOrd(int ord, BytesRef ret) {
|
||||||
|
ret.copyChars(values.getValueByOrd(ord));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef getSafeValueByOrd(int ord) {
|
||||||
|
return new BytesRef(values.getValueByOrd(ord));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.elasticsearch.common.lucene.HashedBytesRef;
|
||||||
|
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface OrdinalsHashedBytesValues extends HashedBytesValues {
|
||||||
|
|
||||||
|
Ordinals.Docs ordinals();
|
||||||
|
|
||||||
|
HashedBytesRef getValueByOrd(int ord);
|
||||||
|
|
||||||
|
HashedBytesRef getSafeValueByOrd(int ord);
|
||||||
|
|
||||||
|
static class BytesBased extends HashedBytesValues.BytesBased implements OrdinalsHashedBytesValues {
|
||||||
|
|
||||||
|
private final OrdinalsBytesValues values;
|
||||||
|
|
||||||
|
public BytesBased(OrdinalsBytesValues values) {
|
||||||
|
super(values);
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Ordinals.Docs ordinals() {
|
||||||
|
return values.ordinals();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef getValueByOrd(int ord) {
|
||||||
|
scratch.bytes = values.getValueByOrd(ord);
|
||||||
|
return scratch.resetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef getSafeValueByOrd(int ord) {
|
||||||
|
return new HashedBytesRef(values.getSafeValueByOrd(ord));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class StringBased extends HashedBytesValues.StringBased implements OrdinalsHashedBytesValues {
|
||||||
|
|
||||||
|
private final OrdinalsStringValues values;
|
||||||
|
|
||||||
|
public StringBased(OrdinalsStringValues values) {
|
||||||
|
super(values);
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Ordinals.Docs ordinals() {
|
||||||
|
return values.ordinals();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef getValueByOrd(int ord) {
|
||||||
|
scratch.bytes.copyChars(values.getValueByOrd(ord));
|
||||||
|
return scratch.resetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef getSafeValueByOrd(int ord) {
|
||||||
|
return new HashedBytesRef(new BytesRef(values.getValueByOrd(ord)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface OrdinalsStringValues extends StringValues {
|
||||||
|
|
||||||
|
Ordinals.Docs ordinals();
|
||||||
|
|
||||||
|
String getValueByOrd(int ord);
|
||||||
|
}
|
@ -0,0 +1,258 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.elasticsearch.index.fielddata.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Script level doc values, the assumption is that any implementation will implement a <code>getValue</code>
|
||||||
|
* and a <code>getValues</code> that return the relevant type that then can be used in scripts.
|
||||||
|
*/
|
||||||
|
public interface ScriptDocValues {
|
||||||
|
|
||||||
|
void setNextDocId(int docId);
|
||||||
|
|
||||||
|
boolean isEmpty();
|
||||||
|
|
||||||
|
static class Strings implements ScriptDocValues {
|
||||||
|
|
||||||
|
private final StringValues values;
|
||||||
|
private int docId;
|
||||||
|
|
||||||
|
public Strings(StringValues values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNextDocId(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return !values.hasValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return values.getValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringArrayRef getValues() {
|
||||||
|
return values.getValues(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Bytes implements ScriptDocValues {
|
||||||
|
|
||||||
|
private final BytesValues values;
|
||||||
|
private int docId;
|
||||||
|
|
||||||
|
public Bytes(BytesValues values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNextDocId(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return !values.hasValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BytesRef getValue() {
|
||||||
|
return values.getValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BytesRefArrayRef getValues() {
|
||||||
|
return values.getValues(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class NumericByte implements ScriptDocValues {
|
||||||
|
|
||||||
|
private final ByteValues values;
|
||||||
|
private int docId;
|
||||||
|
|
||||||
|
public NumericByte(ByteValues values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNextDocId(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return !values.hasValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getValue() {
|
||||||
|
return values.getValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteArrayRef getValues() {
|
||||||
|
return values.getValues(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class NumericShort implements ScriptDocValues {
|
||||||
|
|
||||||
|
private final ShortValues values;
|
||||||
|
private int docId;
|
||||||
|
|
||||||
|
public NumericShort(ShortValues values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNextDocId(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return !values.hasValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getValue() {
|
||||||
|
return values.getValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShortArrayRef getValues() {
|
||||||
|
return values.getValues(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class NumericInteger implements ScriptDocValues {
|
||||||
|
|
||||||
|
private final IntValues values;
|
||||||
|
private int docId;
|
||||||
|
|
||||||
|
public NumericInteger(IntValues values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNextDocId(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return !values.hasValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return values.getValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntArrayRef getValues() {
|
||||||
|
return values.getValues(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class NumericLong implements ScriptDocValues {
|
||||||
|
|
||||||
|
private final LongValues values;
|
||||||
|
private int docId;
|
||||||
|
|
||||||
|
public NumericLong(LongValues values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNextDocId(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return !values.hasValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getValue() {
|
||||||
|
return values.getValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LongArrayRef getValues() {
|
||||||
|
return values.getValues(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class NumericFloat implements ScriptDocValues {
|
||||||
|
|
||||||
|
private final FloatValues values;
|
||||||
|
private int docId;
|
||||||
|
|
||||||
|
public NumericFloat(FloatValues values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNextDocId(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return !values.hasValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getValue() {
|
||||||
|
return values.getValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatArrayRef getValues() {
|
||||||
|
return values.getValues(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class NumericDouble implements ScriptDocValues {
|
||||||
|
|
||||||
|
private final DoubleValues values;
|
||||||
|
private int docId;
|
||||||
|
|
||||||
|
public NumericDouble(DoubleValues values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNextDocId(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return !values.hasValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getValue() {
|
||||||
|
return values.getValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleArrayRef getValues() {
|
||||||
|
return values.getValues(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
198
src/main/java/org/elasticsearch/index/fielddata/ShortValues.java
Normal file
198
src/main/java/org/elasticsearch/index/fielddata/ShortValues.java
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticSearchIllegalStateException;
|
||||||
|
import org.elasticsearch.index.fielddata.util.LongArrayRef;
|
||||||
|
import org.elasticsearch.index.fielddata.util.ShortArrayRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface ShortValues {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is one of the documents in this field data values is multi valued?
|
||||||
|
*/
|
||||||
|
boolean isMultiValued();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is there a value for this doc?
|
||||||
|
*/
|
||||||
|
boolean hasValue(int docId);
|
||||||
|
|
||||||
|
short getValue(int docId);
|
||||||
|
|
||||||
|
short getValueMissing(int docId, short missingValue);
|
||||||
|
|
||||||
|
ShortArrayRef getValues(int docId);
|
||||||
|
|
||||||
|
Iter getIter(int docId);
|
||||||
|
|
||||||
|
void forEachValueInDoc(int docId, ValueInDocProc proc);
|
||||||
|
|
||||||
|
static interface ValueInDocProc {
|
||||||
|
void onValue(int docId, short value);
|
||||||
|
|
||||||
|
void onMissing(int docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static interface Iter {
|
||||||
|
|
||||||
|
boolean hasNext();
|
||||||
|
|
||||||
|
short next();
|
||||||
|
|
||||||
|
static class Empty implements Iter {
|
||||||
|
|
||||||
|
public static final Empty INSTANCE = new Empty();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short next() {
|
||||||
|
throw new ElasticSearchIllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Single implements Iter {
|
||||||
|
|
||||||
|
public short value;
|
||||||
|
public boolean done;
|
||||||
|
|
||||||
|
public Single reset(short value) {
|
||||||
|
this.value = value;
|
||||||
|
this.done = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return !done;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short next() {
|
||||||
|
assert !done;
|
||||||
|
done = true;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LongBased implements ShortValues {
|
||||||
|
|
||||||
|
private final LongValues values;
|
||||||
|
|
||||||
|
private final ShortArrayRef arrayScratch = new ShortArrayRef(new short[1], 1);
|
||||||
|
private final ValueIter iter = new ValueIter();
|
||||||
|
private final Proc proc = new Proc();
|
||||||
|
|
||||||
|
public LongBased(LongValues values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return values.isMultiValued();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return values.hasValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getValue(int docId) {
|
||||||
|
return (short) values.getValue(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short getValueMissing(int docId, short missingValue) {
|
||||||
|
return (short) values.getValueMissing(docId, missingValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShortArrayRef getValues(int docId) {
|
||||||
|
LongArrayRef arrayRef = values.getValues(docId);
|
||||||
|
int size = arrayRef.size();
|
||||||
|
if (size == 0) {
|
||||||
|
return ShortArrayRef.EMPTY;
|
||||||
|
}
|
||||||
|
arrayScratch.reset(size);
|
||||||
|
for (int i = arrayRef.start; i < arrayRef.end; i++) {
|
||||||
|
arrayScratch.values[arrayScratch.end++] = (short) arrayRef.values[i];
|
||||||
|
}
|
||||||
|
return arrayScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return iter.reset(values.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
values.forEachValueInDoc(docId, this.proc.reset(proc));
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ValueIter implements Iter {
|
||||||
|
|
||||||
|
private LongValues.Iter iter;
|
||||||
|
|
||||||
|
public ValueIter reset(LongValues.Iter iter) {
|
||||||
|
this.iter = iter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return iter.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public short next() {
|
||||||
|
return (short) iter.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Proc implements LongValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private ValueInDocProc proc;
|
||||||
|
|
||||||
|
public Proc reset(ValueInDocProc proc) {
|
||||||
|
this.proc = proc;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, long value) {
|
||||||
|
proc.onValue(docId, (short) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticSearchIllegalStateException;
|
||||||
|
import org.elasticsearch.index.fielddata.util.StringArrayRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public interface StringValues {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is one of the documents in this field data values is multi valued?
|
||||||
|
*/
|
||||||
|
boolean isMultiValued();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is there a value for this doc?
|
||||||
|
*/
|
||||||
|
boolean hasValue(int docId);
|
||||||
|
|
||||||
|
String getValue(int docId);
|
||||||
|
|
||||||
|
StringArrayRef getValues(int docId);
|
||||||
|
|
||||||
|
Iter getIter(int docId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go over all the possible values.
|
||||||
|
*/
|
||||||
|
void forEachValueInDoc(int docId, ValueInDocProc proc);
|
||||||
|
|
||||||
|
public static interface ValueInDocProc {
|
||||||
|
void onValue(int docId, String value);
|
||||||
|
|
||||||
|
void onMissing(int docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static interface Iter {
|
||||||
|
|
||||||
|
boolean hasNext();
|
||||||
|
|
||||||
|
String next();
|
||||||
|
|
||||||
|
static class Empty implements Iter {
|
||||||
|
|
||||||
|
public static final Empty INSTANCE = new Empty();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String next() {
|
||||||
|
throw new ElasticSearchIllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Single implements Iter {
|
||||||
|
|
||||||
|
public String value;
|
||||||
|
public boolean done;
|
||||||
|
|
||||||
|
public Single reset(String value) {
|
||||||
|
this.value = value;
|
||||||
|
this.done = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return !done;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String next() {
|
||||||
|
assert !done;
|
||||||
|
done = true;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.fieldcomparator;
|
||||||
|
|
||||||
|
import org.apache.lucene.search.FieldComparator;
|
||||||
|
import org.apache.lucene.search.SortField;
|
||||||
|
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||||
|
import org.elasticsearch.index.fielddata.IndexOrdinalFieldData;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class BytesRefFieldComparatorSource extends IndexFieldData.XFieldComparatorSource {
|
||||||
|
|
||||||
|
private final IndexFieldData indexFieldData;
|
||||||
|
|
||||||
|
public BytesRefFieldComparatorSource(IndexFieldData indexFieldData) {
|
||||||
|
this.indexFieldData = indexFieldData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SortField.Type reducedType() {
|
||||||
|
return SortField.Type.STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FieldComparator<?> newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws IOException {
|
||||||
|
assert fieldname.equals(indexFieldData.getFieldName());
|
||||||
|
if (indexFieldData.valuesOrdered() && indexFieldData instanceof IndexOrdinalFieldData) {
|
||||||
|
return new BytesRefOrdValComparator((IndexOrdinalFieldData) indexFieldData, numHits);
|
||||||
|
}
|
||||||
|
return new BytesRefValComparator(indexFieldData, numHits);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,475 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.fieldcomparator;
|
||||||
|
|
||||||
|
import org.apache.lucene.index.AtomicReaderContext;
|
||||||
|
import org.apache.lucene.search.FieldComparator;
|
||||||
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
||||||
|
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||||
|
import org.elasticsearch.index.fielddata.IndexOrdinalFieldData;
|
||||||
|
import org.elasticsearch.index.fielddata.OrdinalsBytesValues;
|
||||||
|
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts by field's natural Term sort order, using
|
||||||
|
* ordinals. This is functionally equivalent to {@link
|
||||||
|
* org.apache.lucene.search.FieldComparator.TermValComparator}, but it first resolves the string
|
||||||
|
* to their relative ordinal positions (using the index
|
||||||
|
* returned by {@link org.apache.lucene.search.FieldCache#getTermsIndex}), and
|
||||||
|
* does most comparisons using the ordinals. For medium
|
||||||
|
* to large results, this comparator will be much faster
|
||||||
|
* than {@link org.apache.lucene.search.FieldComparator.TermValComparator}. For very small
|
||||||
|
* result sets it may be slower.
|
||||||
|
*/
|
||||||
|
public final class BytesRefOrdValComparator extends FieldComparator<BytesRef> {
|
||||||
|
|
||||||
|
final IndexOrdinalFieldData indexFieldData;
|
||||||
|
|
||||||
|
/* Ords for each slot.
|
||||||
|
@lucene.internal */
|
||||||
|
final int[] ords;
|
||||||
|
|
||||||
|
/* Values for each slot.
|
||||||
|
@lucene.internal */
|
||||||
|
final BytesRef[] values;
|
||||||
|
|
||||||
|
/* Which reader last copied a value into the slot. When
|
||||||
|
we compare two slots, we just compare-by-ord if the
|
||||||
|
readerGen is the same; else we must compare the
|
||||||
|
values (slower).
|
||||||
|
@lucene.internal */
|
||||||
|
final int[] readerGen;
|
||||||
|
|
||||||
|
/* Gen of current reader we are on.
|
||||||
|
@lucene.internal */
|
||||||
|
int currentReaderGen = -1;
|
||||||
|
|
||||||
|
/* Current reader's doc ord/values.
|
||||||
|
@lucene.internal */
|
||||||
|
OrdinalsBytesValues termsIndex;
|
||||||
|
|
||||||
|
/* Bottom slot, or -1 if queue isn't full yet
|
||||||
|
@lucene.internal */
|
||||||
|
int bottomSlot = -1;
|
||||||
|
|
||||||
|
/* Bottom ord (same as ords[bottomSlot] once bottomSlot
|
||||||
|
is set). Cached for faster compares.
|
||||||
|
@lucene.internal */
|
||||||
|
int bottomOrd;
|
||||||
|
|
||||||
|
/* True if current bottom slot matches the current
|
||||||
|
reader.
|
||||||
|
@lucene.internal */
|
||||||
|
boolean bottomSameReader;
|
||||||
|
|
||||||
|
/* Bottom value (same as values[bottomSlot] once
|
||||||
|
bottomSlot is set). Cached for faster compares.
|
||||||
|
@lucene.internal */
|
||||||
|
BytesRef bottomValue;
|
||||||
|
|
||||||
|
final BytesRef tempBR = new BytesRef();
|
||||||
|
|
||||||
|
public BytesRefOrdValComparator(IndexOrdinalFieldData indexFieldData, int numHits) {
|
||||||
|
this.indexFieldData = indexFieldData;
|
||||||
|
ords = new int[numHits];
|
||||||
|
values = new BytesRef[numHits];
|
||||||
|
readerGen = new int[numHits];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(int slot1, int slot2) {
|
||||||
|
if (readerGen[slot1] == readerGen[slot2]) {
|
||||||
|
return ords[slot1] - ords[slot2];
|
||||||
|
}
|
||||||
|
|
||||||
|
final BytesRef val1 = values[slot1];
|
||||||
|
final BytesRef val2 = values[slot2];
|
||||||
|
if (val1 == null) {
|
||||||
|
if (val2 == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
} else if (val2 == null) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return val1.compareTo(val2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareBottom(int doc) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copy(int slot, int doc) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareDocToValue(int doc, BytesRef value) {
|
||||||
|
BytesRef docValue = termsIndex.getValue(doc);
|
||||||
|
if (docValue == null) {
|
||||||
|
if (value == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
} else if (value == null) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return docValue.compareTo(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for specialized (per bit width of the
|
||||||
|
* ords) per-segment comparator. NOTE: this is messy;
|
||||||
|
* we do this only because hotspot can't reliably inline
|
||||||
|
* the underlying array access when looking up doc->ord
|
||||||
|
*
|
||||||
|
* @lucene.internal
|
||||||
|
*/
|
||||||
|
abstract class PerSegmentComparator extends FieldComparator<BytesRef> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FieldComparator<BytesRef> setNextReader(AtomicReaderContext context) throws IOException {
|
||||||
|
return BytesRefOrdValComparator.this.setNextReader(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(int slot1, int slot2) {
|
||||||
|
return BytesRefOrdValComparator.this.compare(slot1, slot2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBottom(final int bottom) {
|
||||||
|
BytesRefOrdValComparator.this.setBottom(bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef value(int slot) {
|
||||||
|
return BytesRefOrdValComparator.this.value(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareValues(BytesRef val1, BytesRef val2) {
|
||||||
|
if (val1 == null) {
|
||||||
|
if (val2 == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
} else if (val2 == null) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return val1.compareTo(val2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareDocToValue(int doc, BytesRef value) {
|
||||||
|
return BytesRefOrdValComparator.this.compareDocToValue(doc, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used per-segment when bit width of doc->ord is 8:
|
||||||
|
private final class ByteOrdComparator extends PerSegmentComparator {
|
||||||
|
private final byte[] readerOrds;
|
||||||
|
private final OrdinalsBytesValues termsIndex;
|
||||||
|
private final int docBase;
|
||||||
|
|
||||||
|
public ByteOrdComparator(byte[] readerOrds, OrdinalsBytesValues termsIndex, int docBase) {
|
||||||
|
this.readerOrds = readerOrds;
|
||||||
|
this.termsIndex = termsIndex;
|
||||||
|
this.docBase = docBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareBottom(int doc) {
|
||||||
|
assert bottomSlot != -1;
|
||||||
|
final int docOrd = (readerOrds[doc] & 0xFF);
|
||||||
|
if (bottomSameReader) {
|
||||||
|
// ord is precisely comparable, even in the equal case
|
||||||
|
return bottomOrd - docOrd;
|
||||||
|
} else if (bottomOrd >= docOrd) {
|
||||||
|
// the equals case always means bottom is > doc
|
||||||
|
// (because we set bottomOrd to the lower bound in
|
||||||
|
// setBottom):
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copy(int slot, int doc) {
|
||||||
|
final int ord = readerOrds[doc] & 0xFF;
|
||||||
|
ords[slot] = ord;
|
||||||
|
if (ord == 0) {
|
||||||
|
values[slot] = null;
|
||||||
|
} else {
|
||||||
|
assert ord > 0;
|
||||||
|
if (values[slot] == null) {
|
||||||
|
values[slot] = new BytesRef();
|
||||||
|
}
|
||||||
|
termsIndex.getValueScratchByOrd(ord, values[slot]);
|
||||||
|
}
|
||||||
|
readerGen[slot] = currentReaderGen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used per-segment when bit width of doc->ord is 16:
|
||||||
|
private final class ShortOrdComparator extends PerSegmentComparator {
|
||||||
|
private final short[] readerOrds;
|
||||||
|
private final OrdinalsBytesValues termsIndex;
|
||||||
|
private final int docBase;
|
||||||
|
|
||||||
|
public ShortOrdComparator(short[] readerOrds, OrdinalsBytesValues termsIndex, int docBase) {
|
||||||
|
this.readerOrds = readerOrds;
|
||||||
|
this.termsIndex = termsIndex;
|
||||||
|
this.docBase = docBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareBottom(int doc) {
|
||||||
|
assert bottomSlot != -1;
|
||||||
|
final int docOrd = (readerOrds[doc] & 0xFFFF);
|
||||||
|
if (bottomSameReader) {
|
||||||
|
// ord is precisely comparable, even in the equal case
|
||||||
|
return bottomOrd - docOrd;
|
||||||
|
} else if (bottomOrd >= docOrd) {
|
||||||
|
// the equals case always means bottom is > doc
|
||||||
|
// (because we set bottomOrd to the lower bound in
|
||||||
|
// setBottom):
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copy(int slot, int doc) {
|
||||||
|
final int ord = readerOrds[doc] & 0xFFFF;
|
||||||
|
ords[slot] = ord;
|
||||||
|
if (ord == 0) {
|
||||||
|
values[slot] = null;
|
||||||
|
} else {
|
||||||
|
assert ord > 0;
|
||||||
|
if (values[slot] == null) {
|
||||||
|
values[slot] = new BytesRef();
|
||||||
|
}
|
||||||
|
termsIndex.getValueScratchByOrd(ord, values[slot]);
|
||||||
|
}
|
||||||
|
readerGen[slot] = currentReaderGen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used per-segment when bit width of doc->ord is 32:
|
||||||
|
private final class IntOrdComparator extends PerSegmentComparator {
|
||||||
|
private final int[] readerOrds;
|
||||||
|
private final OrdinalsBytesValues termsIndex;
|
||||||
|
private final int docBase;
|
||||||
|
|
||||||
|
public IntOrdComparator(int[] readerOrds, OrdinalsBytesValues termsIndex, int docBase) {
|
||||||
|
this.readerOrds = readerOrds;
|
||||||
|
this.termsIndex = termsIndex;
|
||||||
|
this.docBase = docBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareBottom(int doc) {
|
||||||
|
assert bottomSlot != -1;
|
||||||
|
final int docOrd = readerOrds[doc];
|
||||||
|
if (bottomSameReader) {
|
||||||
|
// ord is precisely comparable, even in the equal case
|
||||||
|
return bottomOrd - docOrd;
|
||||||
|
} else if (bottomOrd >= docOrd) {
|
||||||
|
// the equals case always means bottom is > doc
|
||||||
|
// (because we set bottomOrd to the lower bound in
|
||||||
|
// setBottom):
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copy(int slot, int doc) {
|
||||||
|
final int ord = readerOrds[doc];
|
||||||
|
ords[slot] = ord;
|
||||||
|
if (ord == 0) {
|
||||||
|
values[slot] = null;
|
||||||
|
} else {
|
||||||
|
assert ord > 0;
|
||||||
|
if (values[slot] == null) {
|
||||||
|
values[slot] = new BytesRef();
|
||||||
|
}
|
||||||
|
termsIndex.getValueScratchByOrd(ord, values[slot]);
|
||||||
|
}
|
||||||
|
readerGen[slot] = currentReaderGen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used per-segment when bit width is not a native array
|
||||||
|
// size (8, 16, 32):
|
||||||
|
final class AnyOrdComparator extends PerSegmentComparator {
|
||||||
|
private final IndexFieldData fieldData;
|
||||||
|
private final Ordinals.Docs readerOrds;
|
||||||
|
private final OrdinalsBytesValues termsIndex;
|
||||||
|
private final int docBase;
|
||||||
|
|
||||||
|
public AnyOrdComparator(IndexFieldData fieldData, OrdinalsBytesValues termsIndex, int docBase) {
|
||||||
|
this.fieldData = fieldData;
|
||||||
|
this.readerOrds = termsIndex.ordinals();
|
||||||
|
this.termsIndex = termsIndex;
|
||||||
|
this.docBase = docBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareBottom(int doc) {
|
||||||
|
assert bottomSlot != -1;
|
||||||
|
final int docOrd = readerOrds.getOrd(doc);
|
||||||
|
if (bottomSameReader) {
|
||||||
|
// ord is precisely comparable, even in the equal case
|
||||||
|
return bottomOrd - docOrd;
|
||||||
|
} else if (bottomOrd >= docOrd) {
|
||||||
|
// the equals case always means bottom is > doc
|
||||||
|
// (because we set bottomOrd to the lower bound in
|
||||||
|
// setBottom):
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copy(int slot, int doc) {
|
||||||
|
final int ord = readerOrds.getOrd(doc);
|
||||||
|
ords[slot] = ord;
|
||||||
|
if (ord == 0) {
|
||||||
|
values[slot] = null;
|
||||||
|
} else {
|
||||||
|
assert ord > 0;
|
||||||
|
if (values[slot] == null) {
|
||||||
|
values[slot] = new BytesRef();
|
||||||
|
}
|
||||||
|
termsIndex.getValueScratchByOrd(ord, values[slot]);
|
||||||
|
}
|
||||||
|
readerGen[slot] = currentReaderGen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FieldComparator<BytesRef> setNextReader(AtomicReaderContext context) throws IOException {
|
||||||
|
final int docBase = context.docBase;
|
||||||
|
termsIndex = indexFieldData.load(context).getBytesValues();
|
||||||
|
// TODO, we should support sorting on multi valued field, take the best ascending value out of all the values
|
||||||
|
if (termsIndex.isMultiValued()) {
|
||||||
|
throw new ElasticSearchIllegalArgumentException("can't sort on a multi valued field");
|
||||||
|
}
|
||||||
|
final Ordinals.Docs docToOrd = termsIndex.ordinals();
|
||||||
|
Object ordsStorage = docToOrd.ordinals().getBackingStorage();
|
||||||
|
FieldComparator<BytesRef> perSegComp = null;
|
||||||
|
|
||||||
|
if (ordsStorage instanceof byte[]) {
|
||||||
|
perSegComp = new ByteOrdComparator((byte[]) ordsStorage, termsIndex, docBase);
|
||||||
|
} else if (ordsStorage instanceof short[]) {
|
||||||
|
perSegComp = new ShortOrdComparator((short[]) ordsStorage, termsIndex, docBase);
|
||||||
|
} else if (ordsStorage instanceof int[]) {
|
||||||
|
perSegComp = new IntOrdComparator((int[]) ordsStorage, termsIndex, docBase);
|
||||||
|
}
|
||||||
|
// Don't specialize the long[] case since it's not
|
||||||
|
// possible, ie, worse case is MAX_INT-1 docs with
|
||||||
|
// every one having a unique value.
|
||||||
|
|
||||||
|
// TODO: ES - should we optimize for the PackedInts.Reader case as well?
|
||||||
|
if (perSegComp == null) {
|
||||||
|
perSegComp = new AnyOrdComparator(indexFieldData, termsIndex, docBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentReaderGen++;
|
||||||
|
if (bottomSlot != -1) {
|
||||||
|
perSegComp.setBottom(bottomSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
return perSegComp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBottom(final int bottom) {
|
||||||
|
bottomSlot = bottom;
|
||||||
|
|
||||||
|
bottomValue = values[bottomSlot];
|
||||||
|
if (currentReaderGen == readerGen[bottomSlot]) {
|
||||||
|
bottomOrd = ords[bottomSlot];
|
||||||
|
bottomSameReader = true;
|
||||||
|
} else {
|
||||||
|
if (bottomValue == null) {
|
||||||
|
// 0 ord is null for all segments
|
||||||
|
assert ords[bottomSlot] == 0;
|
||||||
|
bottomOrd = 0;
|
||||||
|
bottomSameReader = true;
|
||||||
|
readerGen[bottomSlot] = currentReaderGen;
|
||||||
|
} else {
|
||||||
|
final int index = binarySearch(termsIndex, bottomValue);
|
||||||
|
if (index < 0) {
|
||||||
|
bottomOrd = -index - 2;
|
||||||
|
bottomSameReader = false;
|
||||||
|
} else {
|
||||||
|
bottomOrd = index;
|
||||||
|
// exact value match
|
||||||
|
bottomSameReader = true;
|
||||||
|
readerGen[bottomSlot] = currentReaderGen;
|
||||||
|
ords[bottomSlot] = bottomOrd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef value(int slot) {
|
||||||
|
return values[slot];
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected static int binarySearch(OrdinalsBytesValues a, BytesRef key) {
|
||||||
|
return binarySearch(a, key, 1, a.ordinals().getNumDocs() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected static int binarySearch(OrdinalsBytesValues a, BytesRef key, int low, int high) {
|
||||||
|
|
||||||
|
while (low <= high) {
|
||||||
|
int mid = (low + high) >>> 1;
|
||||||
|
BytesRef midVal = a.getValueByOrd(mid);
|
||||||
|
int cmp;
|
||||||
|
if (midVal != null) {
|
||||||
|
cmp = midVal.compareTo(key);
|
||||||
|
} else {
|
||||||
|
cmp = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmp < 0)
|
||||||
|
low = mid + 1;
|
||||||
|
else if (cmp > 0)
|
||||||
|
high = mid - 1;
|
||||||
|
else
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
|
return -(low + 1);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.fieldcomparator;
|
||||||
|
|
||||||
|
import org.apache.lucene.index.AtomicReaderContext;
|
||||||
|
import org.apache.lucene.search.FieldComparator;
|
||||||
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.elasticsearch.index.fielddata.BytesValues;
|
||||||
|
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts by field's natural Term sort order. All
|
||||||
|
* comparisons are done using BytesRef.compareTo, which is
|
||||||
|
* slow for medium to large result sets but possibly
|
||||||
|
* very fast for very small results sets.
|
||||||
|
*/
|
||||||
|
public final class BytesRefValComparator extends FieldComparator<BytesRef> {
|
||||||
|
|
||||||
|
private final IndexFieldData indexFieldData;
|
||||||
|
private BytesRef[] values;
|
||||||
|
private BytesValues docTerms;
|
||||||
|
private BytesRef bottom;
|
||||||
|
|
||||||
|
BytesRefValComparator(IndexFieldData indexFieldData, int numHits) {
|
||||||
|
values = new BytesRef[numHits];
|
||||||
|
this.indexFieldData = indexFieldData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(int slot1, int slot2) {
|
||||||
|
final BytesRef val1 = values[slot1];
|
||||||
|
final BytesRef val2 = values[slot2];
|
||||||
|
if (val1 == null) {
|
||||||
|
if (val2 == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
} else if (val2 == null) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val1.compareTo(val2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareBottom(int doc) {
|
||||||
|
BytesRef val2 = docTerms.getValue(doc);
|
||||||
|
if (bottom == null) {
|
||||||
|
if (val2 == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
} else if (val2 == null) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return bottom.compareTo(val2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copy(int slot, int doc) {
|
||||||
|
if (values[slot] == null) {
|
||||||
|
values[slot] = new BytesRef();
|
||||||
|
}
|
||||||
|
docTerms.getValueScratch(doc, values[slot]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FieldComparator<BytesRef> setNextReader(AtomicReaderContext context) throws IOException {
|
||||||
|
docTerms = indexFieldData.load(context).getBytesValues();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBottom(final int bottom) {
|
||||||
|
this.bottom = values[bottom];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef value(int slot) {
|
||||||
|
return values[slot];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareValues(BytesRef val1, BytesRef val2) {
|
||||||
|
if (val1 == null) {
|
||||||
|
if (val2 == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
} else if (val2 == null) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return val1.compareTo(val2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareDocToValue(int doc, BytesRef value) {
|
||||||
|
return docTerms.getValue(doc).compareTo(value);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.fieldcomparator;
|
||||||
|
|
||||||
|
import org.apache.lucene.index.AtomicReaderContext;
|
||||||
|
import org.apache.lucene.search.FieldComparator;
|
||||||
|
import org.elasticsearch.index.fielddata.DoubleValues;
|
||||||
|
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class DoubleValuesComparator extends FieldComparator<Double> {
|
||||||
|
|
||||||
|
private final IndexNumericFieldData indexFieldData;
|
||||||
|
private final double missingValue;
|
||||||
|
|
||||||
|
protected final double[] values;
|
||||||
|
private double bottom;
|
||||||
|
private DoubleValues readerValues;
|
||||||
|
|
||||||
|
public DoubleValuesComparator(IndexNumericFieldData indexFieldData, double missingValue, int numHits) {
|
||||||
|
this.indexFieldData = indexFieldData;
|
||||||
|
this.missingValue = missingValue;
|
||||||
|
this.values = new double[numHits];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(int slot1, int slot2) {
|
||||||
|
final double v1 = values[slot1];
|
||||||
|
final double v2 = values[slot2];
|
||||||
|
if (v1 > v2) {
|
||||||
|
return 1;
|
||||||
|
} else if (v1 < v2) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBottom(int slot) {
|
||||||
|
this.bottom = values[slot];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareBottom(int doc) throws IOException {
|
||||||
|
double v2 = readerValues.getValueMissing(doc, missingValue);
|
||||||
|
|
||||||
|
if (bottom > v2) {
|
||||||
|
return 1;
|
||||||
|
} else if (bottom < v2) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copy(int slot, int doc) throws IOException {
|
||||||
|
values[slot] = readerValues.getValueMissing(doc, missingValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FieldComparator<Double> setNextReader(AtomicReaderContext context) throws IOException {
|
||||||
|
this.readerValues = indexFieldData.load(context).getDoubleValues();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Double value(int slot) {
|
||||||
|
return Double.valueOf(values[slot]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareDocToValue(int doc, Double valueObj) throws IOException {
|
||||||
|
final double value = valueObj.doubleValue();
|
||||||
|
double docValue = readerValues.getValueMissing(doc, missingValue);
|
||||||
|
if (docValue < value) {
|
||||||
|
return -1;
|
||||||
|
} else if (docValue > value) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.fieldcomparator;
|
||||||
|
|
||||||
|
import org.apache.lucene.search.FieldComparator;
|
||||||
|
import org.apache.lucene.search.SortField;
|
||||||
|
import org.elasticsearch.common.Nullable;
|
||||||
|
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||||
|
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class DoubleValuesComparatorSource extends IndexFieldData.XFieldComparatorSource {
|
||||||
|
|
||||||
|
private final IndexNumericFieldData indexFieldData;
|
||||||
|
private final Object missingValue;
|
||||||
|
|
||||||
|
public DoubleValuesComparatorSource(IndexNumericFieldData indexFieldData, @Nullable Object missingValue) {
|
||||||
|
this.indexFieldData = indexFieldData;
|
||||||
|
this.missingValue = missingValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SortField.Type reducedType() {
|
||||||
|
return SortField.Type.DOUBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FieldComparator<?> newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws IOException {
|
||||||
|
assert fieldname.equals(indexFieldData.getFieldName());
|
||||||
|
|
||||||
|
double dMissingValue;
|
||||||
|
if (missingValue == null || "_last".equals(missingValue)) {
|
||||||
|
dMissingValue = reversed ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
|
||||||
|
} else if ("_first".equals(missingValue)) {
|
||||||
|
dMissingValue = reversed ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
|
||||||
|
} else {
|
||||||
|
dMissingValue = missingValue instanceof Number ? ((Number) missingValue).doubleValue() : Double.parseDouble(missingValue.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DoubleValuesComparator(indexFieldData, dMissingValue, numHits);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.ordinals;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.RamUsage;
|
||||||
|
import org.elasticsearch.index.fielddata.util.IntArrayRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ordinals that effectively are single valued and map "one to one" to the
|
||||||
|
* doc ids. Note, the docId is incremented by 1 to get the ordinal, since 0
|
||||||
|
* denotes an empty value.
|
||||||
|
*/
|
||||||
|
public class DocIdOrdinals implements Ordinals {
|
||||||
|
|
||||||
|
private final int numDocs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new doc id ordinals.
|
||||||
|
*/
|
||||||
|
public DocIdOrdinals(int numDocs) {
|
||||||
|
this.numDocs = numDocs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getBackingStorage() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getMemorySizeInBytes() {
|
||||||
|
return RamUsage.NUM_BYTES_OBJECT_REF;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDocs() {
|
||||||
|
return numDocs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumOrds() {
|
||||||
|
return numDocs + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Ordinals.Docs ordinals() {
|
||||||
|
return new Docs(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Docs implements Ordinals.Docs {
|
||||||
|
|
||||||
|
private final DocIdOrdinals parent;
|
||||||
|
private final IntArrayRef intsScratch = new IntArrayRef(new int[1]);
|
||||||
|
private final SingleValueIter iter = new SingleValueIter();
|
||||||
|
|
||||||
|
public Docs(DocIdOrdinals parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Ordinals ordinals() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDocs() {
|
||||||
|
return parent.getNumDocs();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumOrds() {
|
||||||
|
return parent.getNumOrds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrd(int docId) {
|
||||||
|
return docId + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntArrayRef getOrds(int docId) {
|
||||||
|
intsScratch.values[0] = docId + 1;
|
||||||
|
return intsScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return iter.reset(docId + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachOrdinalInDoc(int docId, OrdinalInDocProc proc) {
|
||||||
|
proc.onOrdinal(docId, docId + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.ordinals;
|
||||||
|
|
||||||
|
import org.elasticsearch.index.fielddata.util.IntArrayRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class EmptyOrdinals implements Ordinals {
|
||||||
|
|
||||||
|
private final int numDocs;
|
||||||
|
|
||||||
|
public EmptyOrdinals(int numDocs) {
|
||||||
|
this.numDocs = numDocs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getMemorySizeInBytes() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getBackingStorage() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDocs() {
|
||||||
|
return this.numDocs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumOrds() {
|
||||||
|
return numDocs + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Docs ordinals() {
|
||||||
|
return new Docs(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Docs implements Ordinals.Docs {
|
||||||
|
|
||||||
|
private final EmptyOrdinals parent;
|
||||||
|
|
||||||
|
public Docs(EmptyOrdinals parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Ordinals ordinals() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDocs() {
|
||||||
|
return parent.getNumDocs();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumOrds() {
|
||||||
|
return parent.getNumOrds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrd(int docId) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntArrayRef getOrds(int docId) {
|
||||||
|
return IntArrayRef.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return EmptyIter.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachOrdinalInDoc(int docId, OrdinalInDocProc proc) {
|
||||||
|
proc.onOrdinal(docId, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.ordinals;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.RamUsage;
|
||||||
|
import org.elasticsearch.index.fielddata.util.IntArrayRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Flat" multi valued ordinals, the first level array size is as the maximum
|
||||||
|
* values a docId has. Ordinals are populated in order from the first flat array
|
||||||
|
* value to the next.
|
||||||
|
*/
|
||||||
|
public class MultiFlatArrayOrdinals implements Ordinals {
|
||||||
|
|
||||||
|
private ThreadLocal<IntArrayRef> intArrayRefCache = new ThreadLocal<IntArrayRef>() {
|
||||||
|
@Override
|
||||||
|
protected IntArrayRef initialValue() {
|
||||||
|
return new IntArrayRef(new int[ordinals.length]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ordinals with value 0 indicates no value
|
||||||
|
private final int[][] ordinals;
|
||||||
|
private final int numDocs;
|
||||||
|
private final int numOrds;
|
||||||
|
|
||||||
|
private long size = -1;
|
||||||
|
|
||||||
|
public MultiFlatArrayOrdinals(int[][] ordinals, int numOrds) {
|
||||||
|
assert ordinals.length > 0;
|
||||||
|
this.ordinals = ordinals;
|
||||||
|
this.numDocs = ordinals[0].length;
|
||||||
|
this.numOrds = numOrds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getBackingStorage() {
|
||||||
|
return ordinals;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getMemorySizeInBytes() {
|
||||||
|
if (size == -1) {
|
||||||
|
long size = 0;
|
||||||
|
size += RamUsage.NUM_BYTES_ARRAY_HEADER; // for the top level array
|
||||||
|
for (int[] ordinal : ordinals) {
|
||||||
|
size += RamUsage.NUM_BYTES_INT * ordinal.length + RamUsage.NUM_BYTES_ARRAY_HEADER;
|
||||||
|
}
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDocs() {
|
||||||
|
return numDocs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumOrds() {
|
||||||
|
return numOrds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Docs ordinals() {
|
||||||
|
return new Docs(this, ordinals, intArrayRefCache.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Docs implements Ordinals.Docs {
|
||||||
|
|
||||||
|
private final MultiFlatArrayOrdinals parent;
|
||||||
|
private final int[][] ordinals;
|
||||||
|
private final IterImpl iter;
|
||||||
|
|
||||||
|
private final IntArrayRef intsScratch;
|
||||||
|
|
||||||
|
public Docs(MultiFlatArrayOrdinals parent, int[][] ordinals, IntArrayRef intsScratch) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.ordinals = ordinals;
|
||||||
|
this.iter = new IterImpl(ordinals);
|
||||||
|
this.intsScratch = intsScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Ordinals ordinals() {
|
||||||
|
return this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDocs() {
|
||||||
|
return parent.getNumDocs();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumOrds() {
|
||||||
|
return parent.getNumOrds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrd(int docId) {
|
||||||
|
return ordinals[0][docId];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntArrayRef getOrds(int docId) {
|
||||||
|
intsScratch.end = 0;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < ordinals.length; i++) {
|
||||||
|
int ordinal = ordinals[i][docId];
|
||||||
|
if (ordinal == 0) {
|
||||||
|
if (i == 0) return IntArrayRef.EMPTY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
intsScratch.values[i] = ordinal;
|
||||||
|
}
|
||||||
|
intsScratch.end = i;
|
||||||
|
return intsScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return iter.reset(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachOrdinalInDoc(int docId, OrdinalInDocProc proc) {
|
||||||
|
for (int i = 0; i < ordinals.length; i++) {
|
||||||
|
int ordinal = ordinals[i][docId];
|
||||||
|
if (ordinal == 0) {
|
||||||
|
if (i == 0) proc.onOrdinal(docId, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
proc.onOrdinal(docId, ordinal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class IterImpl implements Docs.Iter {
|
||||||
|
|
||||||
|
private final int[][] ordinals;
|
||||||
|
private int docId;
|
||||||
|
private int i;
|
||||||
|
|
||||||
|
public IterImpl(int[][] ordinals) {
|
||||||
|
this.ordinals = ordinals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IterImpl reset(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
this.i = 0;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int next() {
|
||||||
|
if (i >= ordinals.length) return 0;
|
||||||
|
return ordinals[i++][docId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.ordinals;
|
||||||
|
|
||||||
|
import org.elasticsearch.index.fielddata.util.IntArrayRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A thread safe ordinals abstraction. Ordinals can only be positive integers.
|
||||||
|
*/
|
||||||
|
public interface Ordinals {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the backing storage for this ordinals.
|
||||||
|
*/
|
||||||
|
Object getBackingStorage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The memory size this ordinals take.
|
||||||
|
*/
|
||||||
|
long getMemorySizeInBytes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is one of the docs maps to more than one ordinal?
|
||||||
|
*/
|
||||||
|
boolean isMultiValued();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of docs in this ordinals.
|
||||||
|
*/
|
||||||
|
int getNumDocs();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of ordinals.
|
||||||
|
*/
|
||||||
|
int getNumOrds();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a lightweight (non thread safe) view iterator of the ordinals.
|
||||||
|
*/
|
||||||
|
Docs ordinals();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A non thread safe ordinals abstraction, yet very lightweight to create. The idea
|
||||||
|
* is that this gets created for each "iteration" over ordinals.
|
||||||
|
* <p/>
|
||||||
|
* <p>A value of 0 ordinal when iterating indicated "no" value.</p>
|
||||||
|
*/
|
||||||
|
interface Docs {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the original ordinals used to generate this Docs "itereator".
|
||||||
|
*/
|
||||||
|
Ordinals ordinals();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of docs in this ordinals.
|
||||||
|
*/
|
||||||
|
int getNumDocs();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of ordinals.
|
||||||
|
*/
|
||||||
|
int getNumOrds();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is one of the docs maps to more than one ordinal?
|
||||||
|
*/
|
||||||
|
boolean isMultiValued();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ordinal that maps to the relevant docId. If it has no value, returns
|
||||||
|
* <tt>0</tt>.
|
||||||
|
*/
|
||||||
|
int getOrd(int docId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of ordinals matching the docIds, with 0 length one
|
||||||
|
* for a doc with no ordinals.
|
||||||
|
*/
|
||||||
|
IntArrayRef getOrds(int docId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterator of the ordinals that match the docId, with an
|
||||||
|
* empty iterator for a doc with no ordinals.
|
||||||
|
*/
|
||||||
|
Iter getIter(int docId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates over the ordinals associated with a docId. If there are no values,
|
||||||
|
* a callback with a value 0 will be done.
|
||||||
|
*/
|
||||||
|
void forEachOrdinalInDoc(int docId, OrdinalInDocProc proc);
|
||||||
|
|
||||||
|
public static interface OrdinalInDocProc {
|
||||||
|
void onOrdinal(int docId, int ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An iterator over ordinals values.
|
||||||
|
*/
|
||||||
|
interface Iter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the next ordinal. Returning 0 if the iteration is exhausted.
|
||||||
|
*/
|
||||||
|
int next();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class EmptyIter implements Iter {
|
||||||
|
|
||||||
|
public static EmptyIter INSTANCE = new EmptyIter();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int next() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SingleValueIter implements Iter {
|
||||||
|
|
||||||
|
private int value;
|
||||||
|
|
||||||
|
public SingleValueIter reset(int value) {
|
||||||
|
this.value = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int next() {
|
||||||
|
int actual = value;
|
||||||
|
value = 0;
|
||||||
|
return actual;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.ordinals;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.RamUsage;
|
||||||
|
import org.elasticsearch.index.fielddata.util.IntArrayRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class SingleArrayOrdinals implements Ordinals {
|
||||||
|
|
||||||
|
// ordinals with value 0 indicates no value
|
||||||
|
private final int[] ordinals;
|
||||||
|
private final int numOrds;
|
||||||
|
|
||||||
|
private long size = -1;
|
||||||
|
|
||||||
|
public SingleArrayOrdinals(int[] ordinals, int numOrds) {
|
||||||
|
this.ordinals = ordinals;
|
||||||
|
this.numOrds = numOrds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getBackingStorage() {
|
||||||
|
return ordinals;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getMemorySizeInBytes() {
|
||||||
|
if (size == -1) {
|
||||||
|
size = RamUsage.NUM_BYTES_INT * ordinals.length + RamUsage.NUM_BYTES_ARRAY_HEADER;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDocs() {
|
||||||
|
return ordinals.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumOrds() {
|
||||||
|
return numOrds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Docs ordinals() {
|
||||||
|
return new Docs(this, ordinals);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Docs implements Ordinals.Docs {
|
||||||
|
|
||||||
|
private final SingleArrayOrdinals parent;
|
||||||
|
private final int[] ordinals;
|
||||||
|
|
||||||
|
private final IntArrayRef intsScratch = new IntArrayRef(new int[1]);
|
||||||
|
private final SingleValueIter iter = new SingleValueIter();
|
||||||
|
|
||||||
|
public Docs(SingleArrayOrdinals parent, int[] ordinals) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.ordinals = ordinals;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Ordinals ordinals() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDocs() {
|
||||||
|
return parent.getNumDocs();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumOrds() {
|
||||||
|
return parent.getNumOrds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrd(int docId) {
|
||||||
|
return ordinals[docId];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntArrayRef getOrds(int docId) {
|
||||||
|
int ordinal = ordinals[docId];
|
||||||
|
if (ordinal == 0) return IntArrayRef.EMPTY;
|
||||||
|
intsScratch.values[0] = docId;
|
||||||
|
return intsScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return iter.reset(ordinals[docId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachOrdinalInDoc(int docId, OrdinalInDocProc proc) {
|
||||||
|
proc.onOrdinal(docId, ordinals[docId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.ordinals;
|
||||||
|
|
||||||
|
import org.apache.lucene.util.packed.PackedInts;
|
||||||
|
import org.elasticsearch.common.RamUsage;
|
||||||
|
import org.elasticsearch.index.fielddata.util.IntArrayRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class SinglePackedOrdinals implements Ordinals {
|
||||||
|
|
||||||
|
// ordinals with value 0 indicates no value
|
||||||
|
private final PackedInts.Reader reader;
|
||||||
|
private final int numOrds;
|
||||||
|
|
||||||
|
private long size = -1;
|
||||||
|
|
||||||
|
public SinglePackedOrdinals(PackedInts.Reader reader, int numOrds) {
|
||||||
|
this.reader = reader;
|
||||||
|
this.numOrds = numOrds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getBackingStorage() {
|
||||||
|
if (reader.hasArray()) {
|
||||||
|
return reader.getArray();
|
||||||
|
}
|
||||||
|
return reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getMemorySizeInBytes() {
|
||||||
|
if (size == -1) {
|
||||||
|
size = RamUsage.NUM_BYTES_OBJECT_REF + reader.ramBytesUsed();
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDocs() {
|
||||||
|
return reader.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumOrds() {
|
||||||
|
return numOrds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Docs ordinals() {
|
||||||
|
return new Docs(this, reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Docs implements Ordinals.Docs {
|
||||||
|
|
||||||
|
private final SinglePackedOrdinals parent;
|
||||||
|
private final PackedInts.Reader reader;
|
||||||
|
|
||||||
|
private final IntArrayRef intsScratch = new IntArrayRef(new int[1]);
|
||||||
|
private final SingleValueIter iter = new SingleValueIter();
|
||||||
|
|
||||||
|
public Docs(SinglePackedOrdinals parent, PackedInts.Reader reader) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.reader = reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Ordinals ordinals() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDocs() {
|
||||||
|
return parent.getNumDocs();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumOrds() {
|
||||||
|
return parent.getNumOrds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrd(int docId) {
|
||||||
|
return (int) reader.get(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntArrayRef getOrds(int docId) {
|
||||||
|
int ordinal = (int) reader.get(docId);
|
||||||
|
if (ordinal == 0) return IntArrayRef.EMPTY;
|
||||||
|
intsScratch.values[0] = docId;
|
||||||
|
return intsScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return iter.reset((int) reader.get(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachOrdinalInDoc(int docId, OrdinalInDocProc proc) {
|
||||||
|
proc.onOrdinal(docId, (int) reader.get(docId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,673 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.util.BytesRef;
|
||||||
|
import org.elasticsearch.common.RamUsage;
|
||||||
|
import org.elasticsearch.common.lucene.HashedBytesRef;
|
||||||
|
import org.elasticsearch.index.fielddata.*;
|
||||||
|
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||||
|
import org.elasticsearch.index.fielddata.util.BytesRefArrayRef;
|
||||||
|
import org.elasticsearch.index.fielddata.util.IntArrayRef;
|
||||||
|
import org.elasticsearch.index.fielddata.util.StringArrayRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class ConcreteBytesRefAtomicFieldData implements AtomicOrdinalFieldData<ScriptDocValues.Strings> {
|
||||||
|
|
||||||
|
// 0 ordinal in values means no value (its null)
|
||||||
|
private final BytesRef[] values;
|
||||||
|
private final Ordinals ordinals;
|
||||||
|
|
||||||
|
private int[] hashes;
|
||||||
|
private long size = -1;
|
||||||
|
|
||||||
|
public ConcreteBytesRefAtomicFieldData(BytesRef[] values, Ordinals ordinals) {
|
||||||
|
this.values = values;
|
||||||
|
this.ordinals = ordinals;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return ordinals.isMultiValued();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDocs() {
|
||||||
|
return ordinals.getNumDocs();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValuesOrdered() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getMemorySizeInBytes() {
|
||||||
|
if (size == -1) {
|
||||||
|
long size = RamUsage.NUM_BYTES_ARRAY_HEADER;
|
||||||
|
for (BytesRef value : values) {
|
||||||
|
if (value != null) {
|
||||||
|
size += RamUsage.NUM_BYTES_OBJECT_REF + RamUsage.NUM_BYTES_OBJECT_HEADER +
|
||||||
|
RamUsage.NUM_BYTES_ARRAY_HEADER + (value.length + (2 * RamUsage.NUM_BYTES_INT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size += ordinals.getMemorySizeInBytes();
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OrdinalsBytesValues getBytesValues() {
|
||||||
|
return ordinals.isMultiValued() ? new BytesValues.Multi(values, ordinals.ordinals()) : new BytesValues.Single(values, ordinals.ordinals());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OrdinalsHashedBytesValues getHashedBytesValues() {
|
||||||
|
if (hashes == null) {
|
||||||
|
int[] hashes = new int[values.length];
|
||||||
|
for (int i = 0; i < values.length; i++) {
|
||||||
|
BytesRef value = values[i];
|
||||||
|
hashes[i] = value == null ? 0 : value.hashCode();
|
||||||
|
}
|
||||||
|
this.hashes = hashes;
|
||||||
|
}
|
||||||
|
return ordinals.isMultiValued() ? new HashedBytesValues.Multi(values, hashes, ordinals.ordinals()) : new HashedBytesValues.Single(values, hashes, ordinals.ordinals());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OrdinalsStringValues getStringValues() {
|
||||||
|
return ordinals.isMultiValued() ? new StringValues.Multi(values, ordinals.ordinals()) : new StringValues.Single(values, ordinals.ordinals());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScriptDocValues.Strings getScriptValues() {
|
||||||
|
return new ScriptDocValues.Strings(getStringValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
static abstract class BytesValues implements org.elasticsearch.index.fielddata.OrdinalsBytesValues {
|
||||||
|
|
||||||
|
protected final BytesRef[] values;
|
||||||
|
protected final Ordinals.Docs ordinals;
|
||||||
|
|
||||||
|
BytesValues(BytesRef[] values, Ordinals.Docs ordinals) {
|
||||||
|
this.values = values;
|
||||||
|
this.ordinals = ordinals;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Ordinals.Docs ordinals() {
|
||||||
|
return this.ordinals;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef getValueByOrd(int ord) {
|
||||||
|
return values[ord];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef getValueScratchByOrd(int ord, BytesRef ret) {
|
||||||
|
BytesRef value = values[ord];
|
||||||
|
if (value == null) {
|
||||||
|
ret.length = 0;
|
||||||
|
} else {
|
||||||
|
ret.bytes = value.bytes;
|
||||||
|
ret.offset = value.offset;
|
||||||
|
ret.length = value.offset;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef getSafeValueByOrd(int ord) {
|
||||||
|
return values[ord];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return ordinals.getOrd(docId) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef getValue(int docId) {
|
||||||
|
return values[ordinals.getOrd(docId)];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef getValueScratch(int docId, BytesRef ret) {
|
||||||
|
BytesRef value = values[ordinals.getOrd(docId)];
|
||||||
|
if (value == null) {
|
||||||
|
ret.length = 0;
|
||||||
|
} else {
|
||||||
|
ret.bytes = value.bytes;
|
||||||
|
ret.offset = value.offset;
|
||||||
|
ret.length = value.length;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef getValueSafe(int docId) {
|
||||||
|
return values[ordinals.getOrd(docId)];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachSafeValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
forEachValueInDoc(docId, proc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Single extends BytesValues {
|
||||||
|
|
||||||
|
private final BytesRefArrayRef arrayScratch = new BytesRefArrayRef(new BytesRef[1], 1);
|
||||||
|
private final Iter.Single iter = new Iter.Single();
|
||||||
|
|
||||||
|
Single(BytesRef[] values, Ordinals.Docs ordinals) {
|
||||||
|
super(values, ordinals);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRefArrayRef getValues(int docId) {
|
||||||
|
int ord = ordinals.getOrd(docId);
|
||||||
|
if (ord == 0) return BytesRefArrayRef.EMPTY;
|
||||||
|
arrayScratch.values[0] = values[ord];
|
||||||
|
return arrayScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
int ord = ordinals.getOrd(docId);
|
||||||
|
if (ord == 0) return Iter.Empty.INSTANCE;
|
||||||
|
return iter.reset(values[ord]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIterSafe(int docId) {
|
||||||
|
int ord = ordinals.getOrd(docId);
|
||||||
|
if (ord == 0) return Iter.Empty.INSTANCE;
|
||||||
|
return iter.reset(values[ord]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
int ord = ordinals.getOrd(docId);
|
||||||
|
if (ord == 0) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
} else {
|
||||||
|
proc.onValue(docId, values[ord]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Multi extends BytesValues {
|
||||||
|
|
||||||
|
private final BytesRefArrayRef arrayScratch = new BytesRefArrayRef(new BytesRef[10], 0);
|
||||||
|
private final ValuesIter iter;
|
||||||
|
|
||||||
|
Multi(BytesRef[] values, Ordinals.Docs ordinals) {
|
||||||
|
super(values, ordinals);
|
||||||
|
this.iter = new ValuesIter(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRefArrayRef getValues(int docId) {
|
||||||
|
IntArrayRef ords = ordinals.getOrds(docId);
|
||||||
|
int size = ords.size();
|
||||||
|
if (size == 0) return BytesRefArrayRef.EMPTY;
|
||||||
|
|
||||||
|
arrayScratch.reset(size);
|
||||||
|
for (int i = ords.start; i < ords.end; i++) {
|
||||||
|
arrayScratch.values[arrayScratch.end++] = values[ords.values[i]];
|
||||||
|
}
|
||||||
|
return arrayScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return iter.reset(ordinals.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIterSafe(int docId) {
|
||||||
|
return iter.reset(ordinals.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
Ordinals.Docs.Iter iter = ordinals.getIter(docId);
|
||||||
|
int ord = iter.next();
|
||||||
|
if (ord == 0) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
proc.onValue(docId, values[ord]);
|
||||||
|
} while ((ord = iter.next()) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ValuesIter implements Iter {
|
||||||
|
|
||||||
|
private final BytesRef[] values;
|
||||||
|
private Ordinals.Docs.Iter ordsIter;
|
||||||
|
private int ord;
|
||||||
|
|
||||||
|
ValuesIter(BytesRef[] values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValuesIter reset(Ordinals.Docs.Iter ordsIter) {
|
||||||
|
this.ordsIter = ordsIter;
|
||||||
|
this.ord = ordsIter.next();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return ord != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesRef next() {
|
||||||
|
BytesRef value = values[ord];
|
||||||
|
ord = ordsIter.next();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static abstract class HashedBytesValues implements org.elasticsearch.index.fielddata.OrdinalsHashedBytesValues {
|
||||||
|
|
||||||
|
protected final BytesRef[] values;
|
||||||
|
protected final int[] hashes;
|
||||||
|
protected final Ordinals.Docs ordinals;
|
||||||
|
|
||||||
|
protected final HashedBytesRef scratch = new HashedBytesRef();
|
||||||
|
|
||||||
|
HashedBytesValues(BytesRef[] values, int[] hashes, Ordinals.Docs ordinals) {
|
||||||
|
this.values = values;
|
||||||
|
this.hashes = hashes;
|
||||||
|
this.ordinals = ordinals;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Ordinals.Docs ordinals() {
|
||||||
|
return this.ordinals;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef getValueByOrd(int ord) {
|
||||||
|
return scratch.reset(values[ord], hashes[ord]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef getSafeValueByOrd(int ord) {
|
||||||
|
return new HashedBytesRef(values[ord], hashes[ord]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return ordinals.getOrd(docId) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef getValue(int docId) {
|
||||||
|
int ord = ordinals.getOrd(docId);
|
||||||
|
if (ord == 0) return null;
|
||||||
|
return scratch.reset(values[ord], hashes[ord]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef getValueSafe(int docId) {
|
||||||
|
int ord = ordinals.getOrd(docId);
|
||||||
|
if (ord == 0) return null;
|
||||||
|
return new HashedBytesRef(values[ord], hashes[ord]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Single extends HashedBytesValues {
|
||||||
|
|
||||||
|
private final Iter.Single iter = new Iter.Single();
|
||||||
|
|
||||||
|
Single(BytesRef[] values, int[] hashes, Ordinals.Docs ordinals) {
|
||||||
|
super(values, hashes, ordinals);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
int ord = ordinals.getOrd(docId);
|
||||||
|
if (ord == 0) return Iter.Empty.INSTANCE;
|
||||||
|
return iter.reset(scratch.reset(values[ord], hashes[ord]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIterSafe(int docId) {
|
||||||
|
int ord = ordinals.getOrd(docId);
|
||||||
|
if (ord == 0) return Iter.Empty.INSTANCE;
|
||||||
|
return iter.reset(new HashedBytesRef(values[ord], hashes[ord]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
int ord = ordinals.getOrd(docId);
|
||||||
|
if (ord == 0) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
} else {
|
||||||
|
proc.onValue(docId, scratch.reset(values[ord], hashes[ord]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachSafeValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
int ord = ordinals.getOrd(docId);
|
||||||
|
if (ord == 0) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
} else {
|
||||||
|
proc.onValue(docId, new HashedBytesRef(values[ord], hashes[ord]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Multi extends HashedBytesValues {
|
||||||
|
|
||||||
|
private final ValuesIter iter;
|
||||||
|
private final SafeValuesIter safeIter;
|
||||||
|
|
||||||
|
Multi(BytesRef[] values, int[] hashes, Ordinals.Docs ordinals) {
|
||||||
|
super(values, hashes, ordinals);
|
||||||
|
this.iter = new ValuesIter(values, hashes);
|
||||||
|
this.safeIter = new SafeValuesIter(values, hashes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return iter.reset(ordinals.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIterSafe(int docId) {
|
||||||
|
return safeIter.reset(ordinals.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
Ordinals.Docs.Iter iter = ordinals.getIter(docId);
|
||||||
|
int ord = iter.next();
|
||||||
|
if (ord == 0) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
proc.onValue(docId, scratch.reset(values[ord], hashes[ord]));
|
||||||
|
} while ((ord = iter.next()) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachSafeValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
Ordinals.Docs.Iter iter = ordinals.getIter(docId);
|
||||||
|
int ord = iter.next();
|
||||||
|
if (ord == 0) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
proc.onValue(docId, new HashedBytesRef(values[ord], hashes[ord]));
|
||||||
|
} while ((ord = iter.next()) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ValuesIter implements Iter {
|
||||||
|
|
||||||
|
private final BytesRef[] values;
|
||||||
|
private final int[] hashes;
|
||||||
|
private Ordinals.Docs.Iter ordsIter;
|
||||||
|
private int ord;
|
||||||
|
|
||||||
|
private final HashedBytesRef scratch = new HashedBytesRef();
|
||||||
|
|
||||||
|
ValuesIter(BytesRef[] values, int[] hashes) {
|
||||||
|
this.values = values;
|
||||||
|
this.hashes = hashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValuesIter reset(Ordinals.Docs.Iter ordsIter) {
|
||||||
|
this.ordsIter = ordsIter;
|
||||||
|
this.ord = ordsIter.next();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return ord != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef next() {
|
||||||
|
HashedBytesRef value = scratch.reset(values[ord], hashes[ord]);
|
||||||
|
ord = ordsIter.next();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SafeValuesIter implements Iter {
|
||||||
|
|
||||||
|
private final BytesRef[] values;
|
||||||
|
private final int[] hashes;
|
||||||
|
private Ordinals.Docs.Iter ordsIter;
|
||||||
|
private int ord;
|
||||||
|
|
||||||
|
SafeValuesIter(BytesRef[] values, int[] hashes) {
|
||||||
|
this.values = values;
|
||||||
|
this.hashes = hashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SafeValuesIter reset(Ordinals.Docs.Iter ordsIter) {
|
||||||
|
this.ordsIter = ordsIter;
|
||||||
|
this.ord = ordsIter.next();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return ord != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesRef next() {
|
||||||
|
HashedBytesRef value = new HashedBytesRef(values[ord], hashes[ord]);
|
||||||
|
ord = ordsIter.next();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static abstract class StringValues implements OrdinalsStringValues {
|
||||||
|
|
||||||
|
protected final BytesRef[] values;
|
||||||
|
protected final Ordinals.Docs ordinals;
|
||||||
|
|
||||||
|
protected StringValues(BytesRef[] values, Ordinals.Docs ordinals) {
|
||||||
|
this.values = values;
|
||||||
|
this.ordinals = ordinals;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Ordinals.Docs ordinals() {
|
||||||
|
return ordinals;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValueByOrd(int ord) {
|
||||||
|
BytesRef value = values[ord];
|
||||||
|
if (value == null) return null;
|
||||||
|
return value.utf8ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return ordinals.getOrd(docId) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue(int docId) {
|
||||||
|
BytesRef value = values[ordinals.getOrd(docId)];
|
||||||
|
if (value == null) return null;
|
||||||
|
return value.utf8ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Single extends StringValues {
|
||||||
|
|
||||||
|
private final StringArrayRef arrayScratch = new StringArrayRef(new String[1], 1);
|
||||||
|
private final Iter.Single iter = new Iter.Single();
|
||||||
|
|
||||||
|
Single(BytesRef[] values, Ordinals.Docs ordinals) {
|
||||||
|
super(values, ordinals);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringArrayRef getValues(int docId) {
|
||||||
|
int ord = ordinals.getOrd(docId);
|
||||||
|
if (ord == 0) return StringArrayRef.EMPTY;
|
||||||
|
BytesRef value = values[ord];
|
||||||
|
arrayScratch.values[0] = value == null ? null : value.utf8ToString();
|
||||||
|
return arrayScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
int ord = ordinals.getOrd(docId);
|
||||||
|
if (ord == 0) return Iter.Empty.INSTANCE;
|
||||||
|
return iter.reset(values[ord].utf8ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
int ord = ordinals.getOrd(docId);
|
||||||
|
if (ord == 0) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
proc.onValue(docId, values[ord].utf8ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Multi extends StringValues {
|
||||||
|
|
||||||
|
private final StringArrayRef arrayScratch = new StringArrayRef(new String[10], 0);
|
||||||
|
private final ValuesIter iter;
|
||||||
|
|
||||||
|
Multi(BytesRef[] values, Ordinals.Docs ordinals) {
|
||||||
|
super(values, ordinals);
|
||||||
|
iter = new ValuesIter(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringArrayRef getValues(int docId) {
|
||||||
|
IntArrayRef ords = ordinals.getOrds(docId);
|
||||||
|
int size = ords.size();
|
||||||
|
if (size == 0) return StringArrayRef.EMPTY;
|
||||||
|
|
||||||
|
arrayScratch.reset(size);
|
||||||
|
for (int i = ords.start; i < ords.end; i++) {
|
||||||
|
BytesRef value = values[ords.values[i]];
|
||||||
|
arrayScratch.values[arrayScratch.end++] = value == null ? null : value.utf8ToString();
|
||||||
|
}
|
||||||
|
return arrayScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return iter.reset(ordinals.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
Ordinals.Docs.Iter iter = ordinals.getIter(docId);
|
||||||
|
int ord = iter.next();
|
||||||
|
if (ord == 0) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
BytesRef value = values[ord];
|
||||||
|
proc.onValue(docId, value == null ? null : value.utf8ToString());
|
||||||
|
} while ((ord = iter.next()) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ValuesIter implements StringValues.Iter {
|
||||||
|
|
||||||
|
private final BytesRef[] values;
|
||||||
|
private Ordinals.Docs.Iter ordsIter;
|
||||||
|
private int ord;
|
||||||
|
|
||||||
|
ValuesIter(BytesRef[] values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValuesIter reset(Ordinals.Docs.Iter ordsIter) {
|
||||||
|
this.ordsIter = ordsIter;
|
||||||
|
this.ord = ordsIter.next();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return ord != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String next() {
|
||||||
|
BytesRef value = values[ord];
|
||||||
|
ord = ordsIter.next();
|
||||||
|
return value == null ? null : value.utf8ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.*;
|
||||||
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.elasticsearch.ElasticSearchException;
|
||||||
|
import org.elasticsearch.common.Nullable;
|
||||||
|
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.EmptyOrdinals;
|
||||||
|
import org.elasticsearch.index.fielddata.ordinals.MultiFlatArrayOrdinals;
|
||||||
|
import org.elasticsearch.index.fielddata.ordinals.SingleArrayOrdinals;
|
||||||
|
import org.elasticsearch.index.settings.IndexSettings;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class ConcreteBytesRefIndexFieldData extends AbstractIndexFieldData<ConcreteBytesRefAtomicFieldData> implements IndexOrdinalFieldData<ConcreteBytesRefAtomicFieldData> {
|
||||||
|
|
||||||
|
public static class Builder implements IndexFieldData.Builder {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IndexFieldData build(Index index, @IndexSettings Settings indexSettings, String fieldName, FieldDataType type, IndexFieldDataCache cache) {
|
||||||
|
return new ConcreteBytesRefIndexFieldData(index, indexSettings, fieldName, type, cache);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConcreteBytesRefIndexFieldData(Index index, @IndexSettings Settings indexSettings, String fieldName, FieldDataType fieldDataType, IndexFieldDataCache cache) {
|
||||||
|
super(index, indexSettings, fieldName, fieldDataType, cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean valuesOrdered() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConcreteBytesRefAtomicFieldData load(AtomicReaderContext context) {
|
||||||
|
try {
|
||||||
|
return cache.load(context, this);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
if (e instanceof ElasticSearchException) {
|
||||||
|
throw (ElasticSearchException) e;
|
||||||
|
} else {
|
||||||
|
throw new ElasticSearchException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConcreteBytesRefAtomicFieldData loadDirect(AtomicReaderContext context) throws Exception {
|
||||||
|
AtomicReader reader = context.reader();
|
||||||
|
|
||||||
|
Terms terms = reader.terms(getFieldName());
|
||||||
|
if (terms == null) {
|
||||||
|
return new ConcreteBytesRefAtomicFieldData(new BytesRef[1], new EmptyOrdinals(reader.maxDoc()));
|
||||||
|
}
|
||||||
|
|
||||||
|
long size = terms.size();
|
||||||
|
if (size == -1) {
|
||||||
|
size = 1024;
|
||||||
|
}
|
||||||
|
final ArrayList<BytesRef> values = new ArrayList<BytesRef>((int) size);
|
||||||
|
ArrayList<int[]> ordinals = new ArrayList<int[]>();
|
||||||
|
int[] idx = new int[reader.maxDoc()];
|
||||||
|
ordinals.add(new int[reader.maxDoc()]);
|
||||||
|
|
||||||
|
values.add(null); // first "t" indicates null value
|
||||||
|
int termOrd = 1; // current term number
|
||||||
|
|
||||||
|
TermsEnum termsEnum = terms.iterator(null);
|
||||||
|
try {
|
||||||
|
DocsEnum docsEnum = null;
|
||||||
|
for (BytesRef term = termsEnum.next(); term != null; term = termsEnum.next()) {
|
||||||
|
values.add(BytesRef.deepCopyOf(term));
|
||||||
|
docsEnum = termsEnum.docs(reader.getLiveDocs(), docsEnum, 0);
|
||||||
|
for (int docId = docsEnum.nextDoc(); docId != DocsEnum.NO_MORE_DOCS; docId = docsEnum.nextDoc()) {
|
||||||
|
int[] ordinal;
|
||||||
|
if (idx[docId] >= ordinals.size()) {
|
||||||
|
ordinal = new int[reader.maxDoc()];
|
||||||
|
ordinals.add(ordinal);
|
||||||
|
} else {
|
||||||
|
ordinal = ordinals.get(idx[docId]);
|
||||||
|
}
|
||||||
|
ordinal[docId] = termOrd;
|
||||||
|
idx[docId]++;
|
||||||
|
}
|
||||||
|
termOrd++;
|
||||||
|
}
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
if (e.getClass().getName().endsWith("StopFillCacheException")) {
|
||||||
|
// all is well, in case numeric parsers are used.
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ordinals.size() == 1) {
|
||||||
|
// optimizing to DocIdOrdinals which will use less memory removes the "order" notion of ordinals
|
||||||
|
// we can potentially do this, but only for things like facet processes
|
||||||
|
// that don't require order
|
||||||
|
// int[] nativeOrdinals = ordinals.get(0);
|
||||||
|
// boolean allHaveValue = true;
|
||||||
|
// for (int nativeOrdinal : nativeOrdinals) {
|
||||||
|
// if (nativeOrdinal == 0) {
|
||||||
|
// allHaveValue = false;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (allHaveValue) {
|
||||||
|
// BytesRef[] convertedValues = new BytesRef[values.size()];
|
||||||
|
// for (int i = 1; i < nativeOrdinals.length; i++) {
|
||||||
|
// convertedValues[i] = values.get(nativeOrdinals[i]);
|
||||||
|
// }
|
||||||
|
// return new ConcreteBytesRefAtomicFieldData(convertedValues, DocIdOrdinals.INSTANCE);
|
||||||
|
// } else {
|
||||||
|
// return new ConcreteBytesRefAtomicFieldData(values.toArray(new BytesRef[values.size()]), new SingleArrayOrdinals(nativeOrdinals));
|
||||||
|
// }
|
||||||
|
return new ConcreteBytesRefAtomicFieldData(values.toArray(new BytesRef[values.size()]), new SingleArrayOrdinals(ordinals.get(0), termOrd));
|
||||||
|
} else {
|
||||||
|
int[][] nativeOrdinals = new int[ordinals.size()][];
|
||||||
|
for (int i = 0; i < nativeOrdinals.length; i++) {
|
||||||
|
nativeOrdinals[i] = ordinals.get(i);
|
||||||
|
}
|
||||||
|
return new ConcreteBytesRefAtomicFieldData(values.toArray(new BytesRef[values.size()]), new MultiFlatArrayOrdinals(nativeOrdinals, termOrd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue) {
|
||||||
|
// TODO support "missingValue" for sortMissingValue options here...
|
||||||
|
return new BytesRefFieldComparatorSource(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,913 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.util.FixedBitSet;
|
||||||
|
import org.elasticsearch.common.RamUsage;
|
||||||
|
import org.elasticsearch.index.fielddata.*;
|
||||||
|
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||||
|
import org.elasticsearch.index.fielddata.util.DoubleArrayRef;
|
||||||
|
import org.elasticsearch.index.fielddata.util.IntArrayRef;
|
||||||
|
import org.elasticsearch.index.fielddata.util.LongArrayRef;
|
||||||
|
import org.elasticsearch.index.fielddata.util.StringArrayRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public abstract class DoubleArrayAtomicFieldData implements AtomicNumericFieldData {
|
||||||
|
|
||||||
|
protected final double[] values;
|
||||||
|
private final int numDocs;
|
||||||
|
|
||||||
|
protected long size = -1;
|
||||||
|
|
||||||
|
public DoubleArrayAtomicFieldData(double[] values, int numDocs) {
|
||||||
|
this.values = values;
|
||||||
|
this.numDocs = numDocs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDocs() {
|
||||||
|
return numDocs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class WithOrdinals extends DoubleArrayAtomicFieldData {
|
||||||
|
|
||||||
|
private final Ordinals ordinals;
|
||||||
|
|
||||||
|
public WithOrdinals(double[] values, int numDocs, Ordinals ordinals) {
|
||||||
|
super(values, numDocs);
|
||||||
|
this.ordinals = ordinals;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return ordinals.isMultiValued();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValuesOrdered() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getMemorySizeInBytes() {
|
||||||
|
if (size == -1) {
|
||||||
|
size = RamUsage.NUM_BYTES_INT/*size*/ + RamUsage.NUM_BYTES_INT/*numDocs*/ + +RamUsage.NUM_BYTES_ARRAY_HEADER + (values.length * RamUsage.NUM_BYTES_DOUBLE) + ordinals.getMemorySizeInBytes();
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesValues getBytesValues() {
|
||||||
|
return new BytesValues.StringBased(getStringValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesValues getHashedBytesValues() {
|
||||||
|
return new HashedBytesValues.StringBased(getStringValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringValues getStringValues() {
|
||||||
|
return new StringValues(values, ordinals.ordinals());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScriptDocValues getScriptValues() {
|
||||||
|
return new ScriptDocValues.NumericDouble(getDoubleValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteValues getByteValues() {
|
||||||
|
return new ByteValues.LongBased(getLongValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShortValues getShortValues() {
|
||||||
|
return new ShortValues.LongBased(getLongValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntValues getIntValues() {
|
||||||
|
return new IntValues.LongBased(getLongValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LongValues getLongValues() {
|
||||||
|
return new LongValues(values, ordinals.ordinals());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FloatValues getFloatValues() {
|
||||||
|
return new FloatValues.DoubleBased(getDoubleValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DoubleValues getDoubleValues() {
|
||||||
|
return new DoubleValues(values, ordinals.ordinals());
|
||||||
|
}
|
||||||
|
|
||||||
|
static class StringValues implements org.elasticsearch.index.fielddata.StringValues {
|
||||||
|
|
||||||
|
private final double[] values;
|
||||||
|
private final Ordinals.Docs ordinals;
|
||||||
|
|
||||||
|
private final StringArrayRef arrayScratch = new StringArrayRef(new String[1], 1);
|
||||||
|
private final ValuesIter valuesIter;
|
||||||
|
|
||||||
|
StringValues(double[] values, Ordinals.Docs ordinals) {
|
||||||
|
this.values = values;
|
||||||
|
this.ordinals = ordinals;
|
||||||
|
this.valuesIter = new ValuesIter(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return ordinals.getOrd(docId) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return ordinals.isMultiValued();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue(int docId) {
|
||||||
|
int ord = ordinals.getOrd(docId);
|
||||||
|
if (ord == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Double.toString(values[ord]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringArrayRef getValues(int docId) {
|
||||||
|
IntArrayRef ords = ordinals.getOrds(docId);
|
||||||
|
int size = ords.size();
|
||||||
|
if (size == 0) return StringArrayRef.EMPTY;
|
||||||
|
|
||||||
|
arrayScratch.reset(size);
|
||||||
|
for (int i = ords.start; i < ords.end; i++) {
|
||||||
|
arrayScratch.values[arrayScratch.end++] = Double.toString(values[ords.values[i]]);
|
||||||
|
}
|
||||||
|
return arrayScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return valuesIter.reset(ordinals.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
Ordinals.Docs.Iter iter = ordinals.getIter(docId);
|
||||||
|
int ord = iter.next();
|
||||||
|
if (ord == 0) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
proc.onValue(docId, Double.toString(values[ord]));
|
||||||
|
} while ((ord = iter.next()) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ValuesIter implements Iter {
|
||||||
|
|
||||||
|
private final double[] values;
|
||||||
|
private Ordinals.Docs.Iter ordsIter;
|
||||||
|
private int ord;
|
||||||
|
|
||||||
|
ValuesIter(double[] values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValuesIter reset(Ordinals.Docs.Iter ordsIter) {
|
||||||
|
this.ordsIter = ordsIter;
|
||||||
|
this.ord = ordsIter.next();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return ord != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String next() {
|
||||||
|
String value = Double.toString(values[ord]);
|
||||||
|
ord = ordsIter.next();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class LongValues implements org.elasticsearch.index.fielddata.LongValues {
|
||||||
|
|
||||||
|
private final double[] values;
|
||||||
|
private final Ordinals.Docs ordinals;
|
||||||
|
|
||||||
|
private final LongArrayRef arrayScratch = new LongArrayRef(new long[1], 1);
|
||||||
|
private final ValuesIter iter;
|
||||||
|
|
||||||
|
LongValues(double[] values, Ordinals.Docs ordinals) {
|
||||||
|
this.values = values;
|
||||||
|
this.ordinals = ordinals;
|
||||||
|
this.iter = new ValuesIter(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return ordinals.isMultiValued();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return ordinals.getOrd(docId) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getValue(int docId) {
|
||||||
|
return (long) values[ordinals.getOrd(docId)];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getValueMissing(int docId, long missingValue) {
|
||||||
|
int ord = ordinals.getOrd(docId);
|
||||||
|
if (ord == 0) {
|
||||||
|
return missingValue;
|
||||||
|
} else {
|
||||||
|
return (long) values[ord];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LongArrayRef getValues(int docId) {
|
||||||
|
IntArrayRef ords = ordinals.getOrds(docId);
|
||||||
|
int size = ords.size();
|
||||||
|
if (size == 0) return LongArrayRef.EMPTY;
|
||||||
|
|
||||||
|
arrayScratch.reset(size);
|
||||||
|
for (int i = ords.start; i < ords.end; i++) {
|
||||||
|
arrayScratch.values[arrayScratch.end++] = (long) values[ords.values[i]];
|
||||||
|
}
|
||||||
|
return arrayScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return iter.reset(ordinals.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
Ordinals.Docs.Iter iter = ordinals.getIter(docId);
|
||||||
|
int ord = iter.next();
|
||||||
|
if (ord == 0) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
proc.onValue(docId, (long) values[ord]);
|
||||||
|
} while ((ord = iter.next()) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ValuesIter implements LongValues.Iter {
|
||||||
|
|
||||||
|
private final double[] values;
|
||||||
|
private Ordinals.Docs.Iter ordsIter;
|
||||||
|
private int ord;
|
||||||
|
|
||||||
|
ValuesIter(double[] values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValuesIter reset(Ordinals.Docs.Iter ordsIter) {
|
||||||
|
this.ordsIter = ordsIter;
|
||||||
|
this.ord = ordsIter.next();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return ord != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long next() {
|
||||||
|
double value = values[ord];
|
||||||
|
ord = ordsIter.next();
|
||||||
|
return (long) value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DoubleValues implements org.elasticsearch.index.fielddata.DoubleValues {
|
||||||
|
|
||||||
|
private final double[] values;
|
||||||
|
private final Ordinals.Docs ordinals;
|
||||||
|
|
||||||
|
private final DoubleArrayRef arrayScratch = new DoubleArrayRef(new double[1], 1);
|
||||||
|
private final ValuesIter iter;
|
||||||
|
|
||||||
|
DoubleValues(double[] values, Ordinals.Docs ordinals) {
|
||||||
|
this.values = values;
|
||||||
|
this.ordinals = ordinals;
|
||||||
|
this.iter = new ValuesIter(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return ordinals.isMultiValued();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return ordinals.getOrd(docId) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getValue(int docId) {
|
||||||
|
return values[ordinals.getOrd(docId)];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getValueMissing(int docId, double missingValue) {
|
||||||
|
int ord = ordinals.getOrd(docId);
|
||||||
|
if (ord == 0) {
|
||||||
|
return missingValue;
|
||||||
|
} else {
|
||||||
|
return values[ord];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DoubleArrayRef getValues(int docId) {
|
||||||
|
IntArrayRef ords = ordinals.getOrds(docId);
|
||||||
|
int size = ords.size();
|
||||||
|
if (size == 0) return DoubleArrayRef.EMPTY;
|
||||||
|
|
||||||
|
arrayScratch.reset(size);
|
||||||
|
for (int i = ords.start; i < ords.end; i++) {
|
||||||
|
arrayScratch.values[arrayScratch.end++] = values[ords.values[i]];
|
||||||
|
}
|
||||||
|
return arrayScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return iter.reset(ordinals.getIter(docId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
Ordinals.Docs.Iter iter = ordinals.getIter(docId);
|
||||||
|
int ord = iter.next();
|
||||||
|
if (ord == 0) {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
proc.onValue(docId, values[ord]);
|
||||||
|
} while ((ord = iter.next()) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ValuesIter implements DoubleValues.Iter {
|
||||||
|
|
||||||
|
private final double[] values;
|
||||||
|
private Ordinals.Docs.Iter ordsIter;
|
||||||
|
private int ord;
|
||||||
|
|
||||||
|
ValuesIter(double[] values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValuesIter reset(Ordinals.Docs.Iter ordsIter) {
|
||||||
|
this.ordsIter = ordsIter;
|
||||||
|
this.ord = ordsIter.next();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return ord != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double next() {
|
||||||
|
double value = values[ord];
|
||||||
|
ord = ordsIter.next();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single valued case, where not all values are "set", so we have a FixedBitSet that
|
||||||
|
* indicates which values have an actual value.
|
||||||
|
*/
|
||||||
|
public static class SingleFixedSet extends DoubleArrayAtomicFieldData {
|
||||||
|
|
||||||
|
private final FixedBitSet set;
|
||||||
|
|
||||||
|
public SingleFixedSet(double[] values, int numDocs, FixedBitSet set) {
|
||||||
|
super(values, numDocs);
|
||||||
|
this.set = set;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValuesOrdered() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getMemorySizeInBytes() {
|
||||||
|
if (size == -1) {
|
||||||
|
size = RamUsage.NUM_BYTES_ARRAY_HEADER + (values.length * RamUsage.NUM_BYTES_DOUBLE) + (set.getBits().length * RamUsage.NUM_BYTES_LONG);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScriptDocValues getScriptValues() {
|
||||||
|
return new ScriptDocValues.NumericDouble(getDoubleValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesValues getBytesValues() {
|
||||||
|
return new BytesValues.StringBased(getStringValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesValues getHashedBytesValues() {
|
||||||
|
return new HashedBytesValues.StringBased(getStringValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringValues getStringValues() {
|
||||||
|
return new StringValues(values, set);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteValues getByteValues() {
|
||||||
|
return new ByteValues.LongBased(getLongValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShortValues getShortValues() {
|
||||||
|
return new ShortValues.LongBased(getLongValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntValues getIntValues() {
|
||||||
|
return new IntValues.LongBased(getLongValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LongValues getLongValues() {
|
||||||
|
return new LongValues(values, set);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FloatValues getFloatValues() {
|
||||||
|
return new FloatValues.DoubleBased(getDoubleValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DoubleValues getDoubleValues() {
|
||||||
|
return new DoubleValues(values, set);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class StringValues implements org.elasticsearch.index.fielddata.StringValues {
|
||||||
|
|
||||||
|
private final double[] values;
|
||||||
|
private final FixedBitSet set;
|
||||||
|
|
||||||
|
private final StringArrayRef arrayScratch = new StringArrayRef(new String[1], 1);
|
||||||
|
private final Iter.Single iter = new Iter.Single();
|
||||||
|
|
||||||
|
StringValues(double[] values, FixedBitSet set) {
|
||||||
|
this.values = values;
|
||||||
|
this.set = set;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return set.get(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue(int docId) {
|
||||||
|
if (set.get(docId)) {
|
||||||
|
return Double.toString(values[docId]);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringArrayRef getValues(int docId) {
|
||||||
|
if (set.get(docId)) {
|
||||||
|
arrayScratch.values[0] = Double.toString(values[docId]);
|
||||||
|
return arrayScratch;
|
||||||
|
} else {
|
||||||
|
return StringArrayRef.EMPTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
if (set.get(docId)) {
|
||||||
|
return iter.reset(Double.toString(values[docId]));
|
||||||
|
} else {
|
||||||
|
return Iter.Empty.INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
if (set.get(docId)) {
|
||||||
|
proc.onValue(docId, Double.toString(values[docId]));
|
||||||
|
} else {
|
||||||
|
proc.onMissing(docId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class LongValues implements org.elasticsearch.index.fielddata.LongValues {
|
||||||
|
|
||||||
|
private final double[] values;
|
||||||
|
private final FixedBitSet set;
|
||||||
|
|
||||||
|
private final LongArrayRef arrayScratch = new LongArrayRef(new long[1], 1);
|
||||||
|
private final Iter.Single iter = new Iter.Single();
|
||||||
|
|
||||||
|
LongValues(double[] values, FixedBitSet set) {
|
||||||
|
this.values = values;
|
||||||
|
this.set = set;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return set.get(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getValue(int docId) {
|
||||||
|
return (long) values[docId];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getValueMissing(int docId, long missingValue) {
|
||||||
|
if (set.get(docId)) {
|
||||||
|
return (long) values[docId];
|
||||||
|
} else {
|
||||||
|
return missingValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LongArrayRef getValues(int docId) {
|
||||||
|
if (set.get(docId)) {
|
||||||
|
arrayScratch.values[0] = (long) values[docId];
|
||||||
|
return arrayScratch;
|
||||||
|
} else {
|
||||||
|
return LongArrayRef.EMPTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
if (set.get(docId)) {
|
||||||
|
return iter.reset((long) values[docId]);
|
||||||
|
} else {
|
||||||
|
return Iter.Empty.INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
if (set.get(docId)) {
|
||||||
|
proc.onValue(docId, (long) values[docId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DoubleValues implements org.elasticsearch.index.fielddata.DoubleValues {
|
||||||
|
|
||||||
|
private final double[] values;
|
||||||
|
private final FixedBitSet set;
|
||||||
|
|
||||||
|
private final DoubleArrayRef arrayScratch = new DoubleArrayRef(new double[1], 1);
|
||||||
|
private final Iter.Single iter = new Iter.Single();
|
||||||
|
|
||||||
|
DoubleValues(double[] values, FixedBitSet set) {
|
||||||
|
this.values = values;
|
||||||
|
this.set = set;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return set.get(docId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getValue(int docId) {
|
||||||
|
return values[docId];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getValueMissing(int docId, double missingValue) {
|
||||||
|
if (set.get(docId)) {
|
||||||
|
return values[docId];
|
||||||
|
} else {
|
||||||
|
return missingValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DoubleArrayRef getValues(int docId) {
|
||||||
|
if (set.get(docId)) {
|
||||||
|
arrayScratch.values[0] = values[docId];
|
||||||
|
return arrayScratch;
|
||||||
|
} else {
|
||||||
|
return DoubleArrayRef.EMPTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
if (set.get(docId)) {
|
||||||
|
return iter.reset(values[docId]);
|
||||||
|
} else {
|
||||||
|
return Iter.Empty.INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
if (set.get(docId)) {
|
||||||
|
proc.onValue(docId, values[docId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assumes all the values are "set", and docId is used as the index to the value array.
|
||||||
|
*/
|
||||||
|
public static class Single extends DoubleArrayAtomicFieldData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note, here, we assume that there is no offset by 1 from docId, so position 0
|
||||||
|
* is the value for docId 0.
|
||||||
|
*/
|
||||||
|
public Single(double[] values, int numDocs) {
|
||||||
|
super(values, numDocs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValuesOrdered() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getMemorySizeInBytes() {
|
||||||
|
if (size == -1) {
|
||||||
|
size = RamUsage.NUM_BYTES_ARRAY_HEADER + (values.length * RamUsage.NUM_BYTES_DOUBLE);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScriptDocValues getScriptValues() {
|
||||||
|
return new ScriptDocValues.NumericDouble(getDoubleValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytesValues getBytesValues() {
|
||||||
|
return new BytesValues.StringBased(getStringValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedBytesValues getHashedBytesValues() {
|
||||||
|
return new HashedBytesValues.StringBased(getStringValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringValues getStringValues() {
|
||||||
|
return new StringValues(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ByteValues getByteValues() {
|
||||||
|
return new ByteValues.LongBased(getLongValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShortValues getShortValues() {
|
||||||
|
return new ShortValues.LongBased(getLongValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntValues getIntValues() {
|
||||||
|
return new IntValues.LongBased(getLongValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LongValues getLongValues() {
|
||||||
|
return new LongValues(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FloatValues getFloatValues() {
|
||||||
|
return new FloatValues.DoubleBased(getDoubleValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DoubleValues getDoubleValues() {
|
||||||
|
return new DoubleValues(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class StringValues implements org.elasticsearch.index.fielddata.StringValues {
|
||||||
|
|
||||||
|
private final double[] values;
|
||||||
|
|
||||||
|
private final StringArrayRef arrayScratch = new StringArrayRef(new String[1], 1);
|
||||||
|
private final Iter.Single iter = new Iter.Single();
|
||||||
|
|
||||||
|
StringValues(double[] values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue(int docId) {
|
||||||
|
return Double.toString(values[docId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringArrayRef getValues(int docId) {
|
||||||
|
arrayScratch.values[0] = Double.toString(values[docId]);
|
||||||
|
return arrayScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return iter.reset(Double.toString(values[docId]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
proc.onValue(docId, Double.toString(values[docId]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class LongValues implements org.elasticsearch.index.fielddata.LongValues {
|
||||||
|
|
||||||
|
private final double[] values;
|
||||||
|
|
||||||
|
private final LongArrayRef arrayScratch = new LongArrayRef(new long[1], 1);
|
||||||
|
private final Iter.Single iter = new Iter.Single();
|
||||||
|
|
||||||
|
LongValues(double[] values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getValue(int docId) {
|
||||||
|
return (long) values[docId];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getValueMissing(int docId, long missingValue) {
|
||||||
|
return (long) values[docId];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LongArrayRef getValues(int docId) {
|
||||||
|
arrayScratch.values[0] = (long) values[docId];
|
||||||
|
return arrayScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return iter.reset((long) values[docId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
proc.onValue(docId, (long) values[docId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DoubleValues implements org.elasticsearch.index.fielddata.DoubleValues {
|
||||||
|
|
||||||
|
private final double[] values;
|
||||||
|
|
||||||
|
private final DoubleArrayRef arrayScratch = new DoubleArrayRef(new double[1], 1);
|
||||||
|
private final Iter.Single iter = new Iter.Single();
|
||||||
|
|
||||||
|
DoubleValues(double[] values) {
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiValued() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValue(int docId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getValue(int docId) {
|
||||||
|
return values[docId];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getValueMissing(int docId, double missingValue) {
|
||||||
|
return values[docId];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DoubleArrayRef getValues(int docId) {
|
||||||
|
arrayScratch.values[0] = values[docId];
|
||||||
|
return arrayScratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iter getIter(int docId) {
|
||||||
|
return iter.reset(values[docId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||||
|
proc.onValue(docId, values[docId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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 gnu.trove.list.array.TDoubleArrayList;
|
||||||
|
import org.apache.lucene.index.*;
|
||||||
|
import org.apache.lucene.search.FieldCache;
|
||||||
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.apache.lucene.util.FixedBitSet;
|
||||||
|
import org.elasticsearch.ElasticSearchException;
|
||||||
|
import org.elasticsearch.common.Nullable;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.index.Index;
|
||||||
|
import org.elasticsearch.index.fielddata.*;
|
||||||
|
import org.elasticsearch.index.fielddata.fieldcomparator.DoubleValuesComparatorSource;
|
||||||
|
import org.elasticsearch.index.fielddata.ordinals.MultiFlatArrayOrdinals;
|
||||||
|
import org.elasticsearch.index.settings.IndexSettings;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class DoubleArrayIndexFieldData extends AbstractIndexFieldData<DoubleArrayAtomicFieldData> implements IndexNumericFieldData<DoubleArrayAtomicFieldData> {
|
||||||
|
|
||||||
|
public static class Builder implements IndexFieldData.Builder {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IndexFieldData build(Index index, @IndexSettings Settings indexSettings, String fieldName, FieldDataType type, IndexFieldDataCache cache) {
|
||||||
|
return new DoubleArrayIndexFieldData(index, indexSettings, fieldName, type, cache);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleArrayIndexFieldData(Index index, @IndexSettings Settings indexSettings, String fieldName, FieldDataType fieldDataType, IndexFieldDataCache cache) {
|
||||||
|
super(index, indexSettings, fieldName, fieldDataType, cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NumericType getNumericType() {
|
||||||
|
return NumericType.DOUBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean valuesOrdered() {
|
||||||
|
// because we might have single values? we can dynamically update a flag to reflect that
|
||||||
|
// based on the atomic field data loaded
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DoubleArrayAtomicFieldData load(AtomicReaderContext context) {
|
||||||
|
try {
|
||||||
|
return cache.load(context, this);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
if (e instanceof ElasticSearchException) {
|
||||||
|
throw (ElasticSearchException) e;
|
||||||
|
} else {
|
||||||
|
throw new ElasticSearchException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DoubleArrayAtomicFieldData loadDirect(AtomicReaderContext context) throws Exception {
|
||||||
|
AtomicReader reader = context.reader();
|
||||||
|
|
||||||
|
Terms terms = reader.terms(getFieldName());
|
||||||
|
if (terms == null) {
|
||||||
|
return new DoubleArrayAtomicFieldData.Single(new double[0], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: how can we guess the number of terms? numerics end up creating more terms per value...
|
||||||
|
final TDoubleArrayList values = new TDoubleArrayList();
|
||||||
|
ArrayList<int[]> ordinals = new ArrayList<int[]>();
|
||||||
|
int[] idx = new int[reader.maxDoc()];
|
||||||
|
ordinals.add(new int[reader.maxDoc()]);
|
||||||
|
|
||||||
|
values.add(0); // first "t" indicates null value
|
||||||
|
int termOrd = 1; // current term number
|
||||||
|
|
||||||
|
TermsEnum termsEnum = terms.iterator(null);
|
||||||
|
try {
|
||||||
|
DocsEnum docsEnum = null;
|
||||||
|
for (BytesRef term = termsEnum.next(); term != null; term = termsEnum.next()) {
|
||||||
|
values.add(FieldCache.NUMERIC_UTILS_DOUBLE_PARSER.parseDouble(term));
|
||||||
|
docsEnum = termsEnum.docs(reader.getLiveDocs(), docsEnum, 0);
|
||||||
|
for (int docId = docsEnum.nextDoc(); docId != DocsEnum.NO_MORE_DOCS; docId = docsEnum.nextDoc()) {
|
||||||
|
int[] ordinal;
|
||||||
|
if (idx[docId] >= ordinals.size()) {
|
||||||
|
ordinal = new int[reader.maxDoc()];
|
||||||
|
ordinals.add(ordinal);
|
||||||
|
} else {
|
||||||
|
ordinal = ordinals.get(idx[docId]);
|
||||||
|
}
|
||||||
|
ordinal[docId] = termOrd;
|
||||||
|
idx[docId]++;
|
||||||
|
}
|
||||||
|
termOrd++;
|
||||||
|
}
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
if (e.getClass().getName().endsWith("StopFillCacheException")) {
|
||||||
|
// all is well, in case numeric parsers are used.
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ordinals.size() == 1) {
|
||||||
|
int[] nativeOrdinals = ordinals.get(0);
|
||||||
|
FixedBitSet set = new FixedBitSet(reader.maxDoc());
|
||||||
|
double[] sValues = new double[reader.maxDoc()];
|
||||||
|
boolean allHaveValue = true;
|
||||||
|
for (int i = 0; i < nativeOrdinals.length; i++) {
|
||||||
|
int nativeOrdinal = nativeOrdinals[i];
|
||||||
|
if (nativeOrdinal == 0) {
|
||||||
|
allHaveValue = false;
|
||||||
|
} else {
|
||||||
|
set.set(i);
|
||||||
|
sValues[i] = values.get(nativeOrdinal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allHaveValue) {
|
||||||
|
return new DoubleArrayAtomicFieldData.Single(sValues, reader.maxDoc());
|
||||||
|
} else {
|
||||||
|
return new DoubleArrayAtomicFieldData.SingleFixedSet(sValues, reader.maxDoc(), set);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int[][] nativeOrdinals = new int[ordinals.size()][];
|
||||||
|
for (int i = 0; i < nativeOrdinals.length; i++) {
|
||||||
|
nativeOrdinals[i] = ordinals.get(i);
|
||||||
|
}
|
||||||
|
return new DoubleArrayAtomicFieldData.WithOrdinals(values.toArray(new double[values.size()]), reader.maxDoc(), new MultiFlatArrayOrdinals(nativeOrdinals, termOrd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue) {
|
||||||
|
return new DoubleValuesComparatorSource(this, missingValue);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.util;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
|
import org.apache.lucene.util.ArrayUtil;
|
||||||
|
|
||||||
|
import java.util.AbstractList;
|
||||||
|
import java.util.RandomAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class ByteArrayRef extends AbstractList<Byte> implements RandomAccess {
|
||||||
|
|
||||||
|
public static final ByteArrayRef EMPTY = new ByteArrayRef(new byte[0]);
|
||||||
|
|
||||||
|
public byte[] values;
|
||||||
|
public int start;
|
||||||
|
public int end;
|
||||||
|
|
||||||
|
public ByteArrayRef(byte[] values) {
|
||||||
|
this(values, 0, values.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteArrayRef(byte[] values, int length) {
|
||||||
|
this(values, 0, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteArrayRef(byte[] values, int start, int end) {
|
||||||
|
this.values = values;
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset(int newLength) {
|
||||||
|
assert start == 0; // NOTE: senseless if offset != 0
|
||||||
|
end = 0;
|
||||||
|
if (values.length < newLength) {
|
||||||
|
values = new byte[ArrayUtil.oversize(newLength, 32)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return end - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return size() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Byte get(int index) {
|
||||||
|
assert index < size();
|
||||||
|
return values[start + index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
return (target instanceof Byte)
|
||||||
|
&& indexOf(values, (Byte) target, start, end) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int indexOf(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
if (target instanceof Byte) {
|
||||||
|
int i = indexOf(values, (Byte) target, start, end);
|
||||||
|
if (i >= 0) {
|
||||||
|
return i - start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int lastIndexOf(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
if (target instanceof Byte) {
|
||||||
|
int i = lastIndexOf(values, (Byte) target, start, end);
|
||||||
|
if (i >= 0) {
|
||||||
|
return i - start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Byte set(int index, Byte element) {
|
||||||
|
assert index < size();
|
||||||
|
byte oldValue = values[start + index];
|
||||||
|
values[start + index] = element;
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (object == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (object instanceof ByteArrayRef) {
|
||||||
|
ByteArrayRef that = (ByteArrayRef) object;
|
||||||
|
int size = size();
|
||||||
|
if (that.size() != size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
if (values[start + i] != that.values[that.start + i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.equals(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
result = 31 * result + Bytes.hashCode(values[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = new StringBuilder(size() * 10);
|
||||||
|
builder.append('[').append(values[start]);
|
||||||
|
for (int i = start + 1; i < end; i++) {
|
||||||
|
builder.append(", ").append(values[i]);
|
||||||
|
}
|
||||||
|
return builder.append(']').toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int indexOf(byte[] array, byte target, int start, int end) {
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
if (array[i] == target) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int lastIndexOf(byte[] array, byte target, int start, int end) {
|
||||||
|
for (int i = end - 1; i >= start; i--) {
|
||||||
|
if (array[i] == target) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.util;
|
||||||
|
|
||||||
|
import org.apache.lucene.util.ArrayUtil;
|
||||||
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class BytesRefArrayRef {
|
||||||
|
public static final BytesRefArrayRef EMPTY = new BytesRefArrayRef(new BytesRef[0]);
|
||||||
|
|
||||||
|
public BytesRef[] values;
|
||||||
|
public int start;
|
||||||
|
public int end;
|
||||||
|
|
||||||
|
public BytesRefArrayRef(BytesRef[] values) {
|
||||||
|
this(values, 0, values.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BytesRefArrayRef(BytesRef[] values, int length) {
|
||||||
|
this(values, 0, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BytesRefArrayRef(BytesRef[] values, int start, int end) {
|
||||||
|
this.values = values;
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset(int newLength) {
|
||||||
|
assert start == 0; // NOTE: senseless if offset != 0
|
||||||
|
end = 0;
|
||||||
|
if (values.length < newLength) {
|
||||||
|
values = new BytesRef[ArrayUtil.oversize(newLength, 32)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return end - start;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.util;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Doubles;
|
||||||
|
import org.apache.lucene.util.ArrayUtil;
|
||||||
|
|
||||||
|
import java.util.AbstractList;
|
||||||
|
import java.util.RandomAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class DoubleArrayRef extends AbstractList<Double> implements RandomAccess {
|
||||||
|
|
||||||
|
public static final DoubleArrayRef EMPTY = new DoubleArrayRef(new double[0]);
|
||||||
|
|
||||||
|
public double[] values;
|
||||||
|
public int start;
|
||||||
|
public int end;
|
||||||
|
|
||||||
|
public DoubleArrayRef(double[] values) {
|
||||||
|
this(values, 0, values.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleArrayRef(double[] values, int length) {
|
||||||
|
this(values, 0, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleArrayRef(double[] values, int start, int end) {
|
||||||
|
this.values = values;
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset(int newLength) {
|
||||||
|
assert start == 0; // NOTE: senseless if offset != 0
|
||||||
|
end = 0;
|
||||||
|
if (values.length < newLength) {
|
||||||
|
values = new double[ArrayUtil.oversize(newLength, 32)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return end - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return size() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Double get(int index) {
|
||||||
|
assert index < size();
|
||||||
|
return values[start + index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
return (target instanceof Double)
|
||||||
|
&& indexOf(values, (Double) target, start, end) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int indexOf(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
if (target instanceof Double) {
|
||||||
|
int i = indexOf(values, (Double) target, start, end);
|
||||||
|
if (i >= 0) {
|
||||||
|
return i - start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int lastIndexOf(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
if (target instanceof Double) {
|
||||||
|
int i = lastIndexOf(values, (Double) target, start, end);
|
||||||
|
if (i >= 0) {
|
||||||
|
return i - start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Double set(int index, Double element) {
|
||||||
|
assert index < size();
|
||||||
|
double oldValue = values[start + index];
|
||||||
|
values[start + index] = element;
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (object == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (object instanceof DoubleArrayRef) {
|
||||||
|
DoubleArrayRef that = (DoubleArrayRef) object;
|
||||||
|
int size = size();
|
||||||
|
if (that.size() != size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
if (values[start + i] != that.values[that.start + i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.equals(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
result = 31 * result + Doubles.hashCode(values[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = new StringBuilder(size() * 10);
|
||||||
|
builder.append('[').append(values[start]);
|
||||||
|
for (int i = start + 1; i < end; i++) {
|
||||||
|
builder.append(", ").append(values[i]);
|
||||||
|
}
|
||||||
|
return builder.append(']').toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int indexOf(double[] array, double target, int start, int end) {
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
if (array[i] == target) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int lastIndexOf(double[] array, double target, int start, int end) {
|
||||||
|
for (int i = end - 1; i >= start; i--) {
|
||||||
|
if (array[i] == target) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.util;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Floats;
|
||||||
|
import org.apache.lucene.util.ArrayUtil;
|
||||||
|
|
||||||
|
import java.util.AbstractList;
|
||||||
|
import java.util.RandomAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class FloatArrayRef extends AbstractList<Float> implements RandomAccess {
|
||||||
|
|
||||||
|
public static final FloatArrayRef EMPTY = new FloatArrayRef(new float[0]);
|
||||||
|
|
||||||
|
public float[] values;
|
||||||
|
public int start;
|
||||||
|
public int end;
|
||||||
|
|
||||||
|
public FloatArrayRef(float[] values) {
|
||||||
|
this(values, 0, values.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatArrayRef(float[] values, int length) {
|
||||||
|
this(values, 0, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatArrayRef(float[] values, int start, int end) {
|
||||||
|
this.values = values;
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset(int newLength) {
|
||||||
|
assert start == 0; // NOTE: senseless if offset != 0
|
||||||
|
end = 0;
|
||||||
|
if (values.length < newLength) {
|
||||||
|
values = new float[ArrayUtil.oversize(newLength, 32)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return end - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return size() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float get(int index) {
|
||||||
|
assert index < size();
|
||||||
|
return values[start + index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
return (target instanceof Float)
|
||||||
|
&& indexOf(values, (Float) target, start, end) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int indexOf(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
if (target instanceof Float) {
|
||||||
|
int i = indexOf(values, (Float) target, start, end);
|
||||||
|
if (i >= 0) {
|
||||||
|
return i - start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int lastIndexOf(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
if (target instanceof Float) {
|
||||||
|
int i = lastIndexOf(values, (Float) target, start, end);
|
||||||
|
if (i >= 0) {
|
||||||
|
return i - start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float set(int index, Float element) {
|
||||||
|
assert index < size();
|
||||||
|
float oldValue = values[start + index];
|
||||||
|
values[start + index] = element;
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (object == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (object instanceof FloatArrayRef) {
|
||||||
|
FloatArrayRef that = (FloatArrayRef) object;
|
||||||
|
int size = size();
|
||||||
|
if (that.size() != size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
if (values[start + i] != that.values[that.start + i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.equals(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
result = 31 * result + Floats.hashCode(values[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = new StringBuilder(size() * 10);
|
||||||
|
builder.append('[').append(values[start]);
|
||||||
|
for (int i = start + 1; i < end; i++) {
|
||||||
|
builder.append(", ").append(values[i]);
|
||||||
|
}
|
||||||
|
return builder.append(']').toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int indexOf(float[] array, float target, int start, int end) {
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
if (array[i] == target) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int lastIndexOf(float[] array, float target, int start, int end) {
|
||||||
|
for (int i = end - 1; i >= start; i--) {
|
||||||
|
if (array[i] == target) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.util;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Ints;
|
||||||
|
import org.apache.lucene.util.ArrayUtil;
|
||||||
|
|
||||||
|
import java.util.AbstractList;
|
||||||
|
import java.util.RandomAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class IntArrayRef extends AbstractList<Integer> implements RandomAccess {
|
||||||
|
|
||||||
|
public static final IntArrayRef EMPTY = new IntArrayRef(new int[0]);
|
||||||
|
|
||||||
|
public int[] values;
|
||||||
|
public int start;
|
||||||
|
public int end;
|
||||||
|
|
||||||
|
public IntArrayRef(int[] values) {
|
||||||
|
this(values, 0, values.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntArrayRef(int[] values, int length) {
|
||||||
|
this(values, 0, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntArrayRef(int[] values, int start, int end) {
|
||||||
|
this.values = values;
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset(int newLength) {
|
||||||
|
assert start == 0; // NOTE: senseless if offset != 0
|
||||||
|
end = 0;
|
||||||
|
if (values.length < newLength) {
|
||||||
|
values = new int[ArrayUtil.oversize(newLength, 32)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return end - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return size() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer get(int index) {
|
||||||
|
assert index < size();
|
||||||
|
return values[start + index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
return (target instanceof Integer)
|
||||||
|
&& indexOf(values, (Integer) target, start, end) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int indexOf(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
if (target instanceof Integer) {
|
||||||
|
int i = indexOf(values, (Integer) target, start, end);
|
||||||
|
if (i >= 0) {
|
||||||
|
return i - start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int lastIndexOf(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
if (target instanceof Integer) {
|
||||||
|
int i = lastIndexOf(values, (Integer) target, start, end);
|
||||||
|
if (i >= 0) {
|
||||||
|
return i - start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer set(int index, Integer element) {
|
||||||
|
assert index < size();
|
||||||
|
int oldValue = values[start + index];
|
||||||
|
values[start + index] = element;
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (object == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (object instanceof IntArrayRef) {
|
||||||
|
IntArrayRef that = (IntArrayRef) object;
|
||||||
|
int size = size();
|
||||||
|
if (that.size() != size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
if (values[start + i] != that.values[that.start + i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.equals(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
result = 31 * result + Ints.hashCode(values[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = new StringBuilder(size() * 10);
|
||||||
|
builder.append('[').append(values[start]);
|
||||||
|
for (int i = start + 1; i < end; i++) {
|
||||||
|
builder.append(", ").append(values[i]);
|
||||||
|
}
|
||||||
|
return builder.append(']').toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int indexOf(int[] array, int target, int start, int end) {
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
if (array[i] == target) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int lastIndexOf(int[] array, int target, int start, int end) {
|
||||||
|
for (int i = end - 1; i >= start; i--) {
|
||||||
|
if (array[i] == target) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.util;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Longs;
|
||||||
|
import org.apache.lucene.util.ArrayUtil;
|
||||||
|
|
||||||
|
import java.util.AbstractList;
|
||||||
|
import java.util.RandomAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class LongArrayRef extends AbstractList<Long> implements RandomAccess {
|
||||||
|
|
||||||
|
public static final LongArrayRef EMPTY = new LongArrayRef(new long[0]);
|
||||||
|
|
||||||
|
public long[] values;
|
||||||
|
public int start;
|
||||||
|
public int end;
|
||||||
|
|
||||||
|
public LongArrayRef(long[] values) {
|
||||||
|
this(values, 0, values.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LongArrayRef(long[] values, int length) {
|
||||||
|
this(values, 0, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LongArrayRef(long[] values, int start, int end) {
|
||||||
|
this.values = values;
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset(int newLength) {
|
||||||
|
assert start == 0; // NOTE: senseless if offset != 0
|
||||||
|
end = 0;
|
||||||
|
if (values.length < newLength) {
|
||||||
|
values = new long[ArrayUtil.oversize(newLength, 32)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return end - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return size() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long get(int index) {
|
||||||
|
assert index < size();
|
||||||
|
return values[start + index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
return (target instanceof Long)
|
||||||
|
&& indexOf(values, (Long) target, start, end) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int indexOf(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
if (target instanceof Long) {
|
||||||
|
int i = indexOf(values, (Long) target, start, end);
|
||||||
|
if (i >= 0) {
|
||||||
|
return i - start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int lastIndexOf(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
if (target instanceof Long) {
|
||||||
|
int i = lastIndexOf(values, (Long) target, start, end);
|
||||||
|
if (i >= 0) {
|
||||||
|
return i - start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long set(int index, Long element) {
|
||||||
|
assert index < size();
|
||||||
|
long oldValue = values[start + index];
|
||||||
|
values[start + index] = element;
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (object == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (object instanceof LongArrayRef) {
|
||||||
|
LongArrayRef that = (LongArrayRef) object;
|
||||||
|
int size = size();
|
||||||
|
if (that.size() != size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
if (values[start + i] != that.values[that.start + i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.equals(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
result = 31 * result + Longs.hashCode(values[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = new StringBuilder(size() * 10);
|
||||||
|
builder.append('[').append(values[start]);
|
||||||
|
for (int i = start + 1; i < end; i++) {
|
||||||
|
builder.append(", ").append(values[i]);
|
||||||
|
}
|
||||||
|
return builder.append(']').toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int indexOf(long[] array, long target, int start, int end) {
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
if (array[i] == target) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int lastIndexOf(long[] array, long target, int start, int end) {
|
||||||
|
for (int i = end - 1; i >= start; i--) {
|
||||||
|
if (array[i] == target) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.util;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Shorts;
|
||||||
|
import org.apache.lucene.util.ArrayUtil;
|
||||||
|
|
||||||
|
import java.util.AbstractList;
|
||||||
|
import java.util.RandomAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class ShortArrayRef extends AbstractList<Short> implements RandomAccess {
|
||||||
|
|
||||||
|
public static final ShortArrayRef EMPTY = new ShortArrayRef(new short[0]);
|
||||||
|
|
||||||
|
public short[] values;
|
||||||
|
public int start;
|
||||||
|
public int end;
|
||||||
|
|
||||||
|
public ShortArrayRef(short[] values) {
|
||||||
|
this(values, 0, values.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShortArrayRef(short[] values, int length) {
|
||||||
|
this(values, 0, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShortArrayRef(short[] values, int start, int end) {
|
||||||
|
this.values = values;
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset(int newLength) {
|
||||||
|
assert start == 0; // NOTE: senseless if offset != 0
|
||||||
|
end = 0;
|
||||||
|
if (values.length < newLength) {
|
||||||
|
values = new short[ArrayUtil.oversize(newLength, 32)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return end - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return size() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Short get(int index) {
|
||||||
|
assert index < size();
|
||||||
|
return values[start + index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
return (target instanceof Short)
|
||||||
|
&& indexOf(values, (Short) target, start, end) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int indexOf(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
if (target instanceof Short) {
|
||||||
|
int i = indexOf(values, (Short) target, start, end);
|
||||||
|
if (i >= 0) {
|
||||||
|
return i - start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int lastIndexOf(Object target) {
|
||||||
|
// Overridden to prevent a ton of boxing
|
||||||
|
if (target instanceof Short) {
|
||||||
|
int i = lastIndexOf(values, (Short) target, start, end);
|
||||||
|
if (i >= 0) {
|
||||||
|
return i - start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Short set(int index, Short element) {
|
||||||
|
assert index < size();
|
||||||
|
short oldValue = values[start + index];
|
||||||
|
values[start + index] = element;
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (object == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (object instanceof ShortArrayRef) {
|
||||||
|
ShortArrayRef that = (ShortArrayRef) object;
|
||||||
|
int size = size();
|
||||||
|
if (that.size() != size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
if (values[start + i] != that.values[that.start + i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.equals(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
result = 31 * result + Shorts.hashCode(values[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = new StringBuilder(size() * 10);
|
||||||
|
builder.append('[').append(values[start]);
|
||||||
|
for (int i = start + 1; i < end; i++) {
|
||||||
|
builder.append(", ").append(values[i]);
|
||||||
|
}
|
||||||
|
return builder.append(']').toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int indexOf(short[] array, short target, int start, int end) {
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
if (array[i] == target) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int lastIndexOf(short[] array, short target, int start, int end) {
|
||||||
|
for (int i = end - 1; i >= start; i--) {
|
||||||
|
if (array[i] == target) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.util;
|
||||||
|
|
||||||
|
import org.apache.lucene.util.ArrayUtil;
|
||||||
|
|
||||||
|
import java.util.AbstractList;
|
||||||
|
import java.util.RandomAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class StringArrayRef extends AbstractList<String> implements RandomAccess {
|
||||||
|
|
||||||
|
public static final StringArrayRef EMPTY = new StringArrayRef(new String[0]);
|
||||||
|
|
||||||
|
public String[] values;
|
||||||
|
public int start;
|
||||||
|
public int end;
|
||||||
|
|
||||||
|
public StringArrayRef(String[] values) {
|
||||||
|
this(values, 0, values.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringArrayRef(String[] values, int length) {
|
||||||
|
this(values, 0, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringArrayRef(String[] values, int start, int end) {
|
||||||
|
this.values = values;
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset(int newLength) {
|
||||||
|
assert start == 0; // NOTE: senseless if offset != 0
|
||||||
|
end = 0;
|
||||||
|
if (values.length < newLength) {
|
||||||
|
values = new String[ArrayUtil.oversize(newLength, 32)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return end - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return size() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String get(int index) {
|
||||||
|
assert index >= 0 && index < size();
|
||||||
|
return values[start + index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(Object target) {
|
||||||
|
String sTarget = target.toString();
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
if (values[i].equals(sTarget)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int indexOf(Object target) {
|
||||||
|
String sTarget = target.toString();
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
if (values[i].equals(sTarget)) return (i - start);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int lastIndexOf(Object target) {
|
||||||
|
String sTarget = target.toString();
|
||||||
|
for (int i = end - 1; i >= start; i--) {
|
||||||
|
if (values[i].equals(sTarget)) return (i - start);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String set(int index, String element) {
|
||||||
|
assert index >= 0 && index < size();
|
||||||
|
String oldValue = values[start + index];
|
||||||
|
values[start + index] = element;
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (object == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (object instanceof StringArrayRef) {
|
||||||
|
StringArrayRef that = (StringArrayRef) object;
|
||||||
|
int size = size();
|
||||||
|
if (that.size() != size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
if (!values[start + i].equals(that.values[that.start + i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.equals(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
result = 31 * result + values[i].hashCode();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = new StringBuilder(size() * 10);
|
||||||
|
builder.append('[').append(values[start]);
|
||||||
|
for (int i = start + 1; i < end; i++) {
|
||||||
|
builder.append(", ").append(values[i]);
|
||||||
|
}
|
||||||
|
return builder.append(']').toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,413 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.test.unit.index.fielddata;
|
||||||
|
|
||||||
|
import org.apache.lucene.analysis.standard.StandardAnalyzer;
|
||||||
|
import org.apache.lucene.index.*;
|
||||||
|
import org.apache.lucene.store.RAMDirectory;
|
||||||
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.elasticsearch.common.lucene.HashedBytesRef;
|
||||||
|
import org.elasticsearch.common.lucene.Lucene;
|
||||||
|
import org.elasticsearch.index.Index;
|
||||||
|
import org.elasticsearch.index.fielddata.*;
|
||||||
|
import org.testng.annotations.AfterMethod;
|
||||||
|
import org.testng.annotations.BeforeMethod;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.sameInstance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public abstract class AbstractFieldDataTests {
|
||||||
|
|
||||||
|
protected IndexFieldDataService ifdService;
|
||||||
|
protected IndexWriter writer;
|
||||||
|
protected AtomicReaderContext readerContext;
|
||||||
|
|
||||||
|
protected abstract FieldDataType getFieldDataType();
|
||||||
|
|
||||||
|
public <IFD extends IndexFieldData> IFD getForField(String fieldName) {
|
||||||
|
return ifdService.getForField(fieldName, getFieldDataType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeMethod
|
||||||
|
public void setup() throws Exception {
|
||||||
|
ifdService = new IndexFieldDataService(new Index("test"));
|
||||||
|
writer = new IndexWriter(new RAMDirectory(), new IndexWriterConfig(Lucene.VERSION, new StandardAnalyzer(Lucene.VERSION)));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AtomicReaderContext refreshReader() throws Exception {
|
||||||
|
if (readerContext != null) {
|
||||||
|
readerContext.reader().close();
|
||||||
|
}
|
||||||
|
AtomicReader reader = new SlowCompositeReaderWrapper(DirectoryReader.open(writer, true));
|
||||||
|
readerContext = reader.getContext();
|
||||||
|
return readerContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterMethod
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
if (readerContext != null) {
|
||||||
|
readerContext.reader().close();
|
||||||
|
}
|
||||||
|
writer.close();
|
||||||
|
ifdService.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BytesValuesVerifierProc implements BytesValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private static final BytesRef MISSING = new BytesRef();
|
||||||
|
|
||||||
|
private final int docId;
|
||||||
|
private final List<BytesRef> expected = new ArrayList<BytesRef>();
|
||||||
|
|
||||||
|
private int idx;
|
||||||
|
|
||||||
|
BytesValuesVerifierProc(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BytesValuesVerifierProc addExpected(String value) {
|
||||||
|
expected.add(new BytesRef(value));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BytesValuesVerifierProc addExpected(BytesRef value) {
|
||||||
|
expected.add(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BytesValuesVerifierProc addMissing() {
|
||||||
|
expected.add(MISSING);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, BytesRef value) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(value, equalTo(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(MISSING, sameInstance(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HashedBytesValuesVerifierProc implements HashedBytesValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private static final HashedBytesRef MISSING = new HashedBytesRef();
|
||||||
|
|
||||||
|
private final int docId;
|
||||||
|
private final List<HashedBytesRef> expected = new ArrayList<HashedBytesRef>();
|
||||||
|
|
||||||
|
private int idx;
|
||||||
|
|
||||||
|
HashedBytesValuesVerifierProc(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashedBytesValuesVerifierProc addExpected(String value) {
|
||||||
|
expected.add(new HashedBytesRef(value));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashedBytesValuesVerifierProc addExpected(BytesRef value) {
|
||||||
|
expected.add(new HashedBytesRef(value));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashedBytesValuesVerifierProc addMissing() {
|
||||||
|
expected.add(MISSING);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, HashedBytesRef value) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(value, equalTo(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(MISSING, sameInstance(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class StringValuesVerifierProc implements StringValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private static final String MISSING = new String();
|
||||||
|
|
||||||
|
private final int docId;
|
||||||
|
private final List<String> expected = new ArrayList<String>();
|
||||||
|
|
||||||
|
private int idx;
|
||||||
|
|
||||||
|
StringValuesVerifierProc(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringValuesVerifierProc addExpected(String value) {
|
||||||
|
expected.add(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringValuesVerifierProc addMissing() {
|
||||||
|
expected.add(MISSING);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, String value) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(value, equalTo(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(MISSING, sameInstance(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LongValuesVerifierProc implements LongValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private static final Long MISSING = new Long(0);
|
||||||
|
|
||||||
|
private final int docId;
|
||||||
|
private final List<Long> expected = new ArrayList<Long>();
|
||||||
|
|
||||||
|
private int idx;
|
||||||
|
|
||||||
|
LongValuesVerifierProc(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LongValuesVerifierProc addExpected(long value) {
|
||||||
|
expected.add(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LongValuesVerifierProc addMissing() {
|
||||||
|
expected.add(MISSING);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, long value) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(value, equalTo(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(MISSING, sameInstance(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DoubleValuesVerifierProc implements DoubleValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private static final Double MISSING = new Double(0);
|
||||||
|
|
||||||
|
private final int docId;
|
||||||
|
private final List<Double> expected = new ArrayList<Double>();
|
||||||
|
|
||||||
|
private int idx;
|
||||||
|
|
||||||
|
DoubleValuesVerifierProc(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleValuesVerifierProc addExpected(double value) {
|
||||||
|
expected.add(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleValuesVerifierProc addMissing() {
|
||||||
|
expected.add(MISSING);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, double value) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(value, equalTo(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(MISSING, sameInstance(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByteValuesVerifierProc implements ByteValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private static final Byte MISSING = new Byte((byte) 0);
|
||||||
|
|
||||||
|
private final int docId;
|
||||||
|
private final List<Byte> expected = new ArrayList<Byte>();
|
||||||
|
|
||||||
|
private int idx;
|
||||||
|
|
||||||
|
ByteValuesVerifierProc(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteValuesVerifierProc addExpected(byte value) {
|
||||||
|
expected.add(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteValuesVerifierProc addMissing() {
|
||||||
|
expected.add(MISSING);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, byte value) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(value, equalTo(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(MISSING, sameInstance(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ShortValuesVerifierProc implements ShortValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private static final Short MISSING = new Short((byte) 0);
|
||||||
|
|
||||||
|
private final int docId;
|
||||||
|
private final List<Short> expected = new ArrayList<Short>();
|
||||||
|
|
||||||
|
private int idx;
|
||||||
|
|
||||||
|
ShortValuesVerifierProc(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShortValuesVerifierProc addExpected(short value) {
|
||||||
|
expected.add(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShortValuesVerifierProc addMissing() {
|
||||||
|
expected.add(MISSING);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, short value) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(value, equalTo(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(MISSING, sameInstance(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class IntValuesVerifierProc implements IntValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private static final Integer MISSING = new Integer(0);
|
||||||
|
|
||||||
|
private final int docId;
|
||||||
|
private final List<Integer> expected = new ArrayList<Integer>();
|
||||||
|
|
||||||
|
private int idx;
|
||||||
|
|
||||||
|
IntValuesVerifierProc(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntValuesVerifierProc addExpected(int value) {
|
||||||
|
expected.add(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntValuesVerifierProc addMissing() {
|
||||||
|
expected.add(MISSING);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, int value) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(value, equalTo(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(MISSING, sameInstance(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FloatValuesVerifierProc implements FloatValues.ValueInDocProc {
|
||||||
|
|
||||||
|
private static final Float MISSING = new Float(0);
|
||||||
|
|
||||||
|
private final int docId;
|
||||||
|
private final List<Float> expected = new ArrayList<Float>();
|
||||||
|
|
||||||
|
private int idx;
|
||||||
|
|
||||||
|
FloatValuesVerifierProc(int docId) {
|
||||||
|
this.docId = docId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatValuesVerifierProc addExpected(float value) {
|
||||||
|
expected.add(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatValuesVerifierProc addMissing() {
|
||||||
|
expected.add(MISSING);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(int docId, float value) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(value, equalTo(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissing(int docId) {
|
||||||
|
assertThat(docId, equalTo(this.docId));
|
||||||
|
assertThat(MISSING, sameInstance(expected.get(idx++)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.test.unit.index.fielddata;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import org.elasticsearch.index.fielddata.FieldDataType;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public class ConcreteBytesStringFieldDataTests extends StringFieldDataTests {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected FieldDataType getFieldDataType() {
|
||||||
|
return new FieldDataType("string", "concrete_bytes", ImmutableMap.<String, String>of());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.test.unit.index.fielddata;
|
||||||
|
|
||||||
|
import org.elasticsearch.index.fielddata.FieldDataType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class DoubleFieldDataTests extends NumericFieldDataTests {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected FieldDataType getFieldDataType() {
|
||||||
|
return new FieldDataType("double");
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,741 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to ElasticSearch and Shay Banon 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.test.unit.index.fielddata;
|
||||||
|
|
||||||
|
import org.apache.lucene.document.Document;
|
||||||
|
import org.apache.lucene.document.Field;
|
||||||
|
import org.apache.lucene.document.StringField;
|
||||||
|
import org.apache.lucene.index.AtomicReaderContext;
|
||||||
|
import org.apache.lucene.search.*;
|
||||||
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.elasticsearch.common.lucene.HashedBytesRef;
|
||||||
|
import org.elasticsearch.index.fielddata.*;
|
||||||
|
import org.elasticsearch.index.fielddata.util.BytesRefArrayRef;
|
||||||
|
import org.elasticsearch.index.fielddata.util.StringArrayRef;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public abstract class StringFieldDataTests extends AbstractFieldDataTests {
|
||||||
|
|
||||||
|
protected String one() {
|
||||||
|
return "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String two() {
|
||||||
|
return "2";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String three() {
|
||||||
|
return "3";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String four() {
|
||||||
|
return "4";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fillSingleValueAllSet() throws Exception {
|
||||||
|
Document d = new Document();
|
||||||
|
d.add(new StringField("_id", "1", Field.Store.NO));
|
||||||
|
d.add(new StringField("value", "2", Field.Store.NO));
|
||||||
|
writer.addDocument(d);
|
||||||
|
|
||||||
|
d = new Document();
|
||||||
|
d.add(new StringField("_id", "1", Field.Store.NO));
|
||||||
|
d.add(new StringField("value", "1", Field.Store.NO));
|
||||||
|
writer.addDocument(d);
|
||||||
|
|
||||||
|
d = new Document();
|
||||||
|
d.add(new StringField("_id", "3", Field.Store.NO));
|
||||||
|
d.add(new StringField("value", "3", Field.Store.NO));
|
||||||
|
writer.addDocument(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleValueAllSet() throws Exception {
|
||||||
|
fillSingleValueAllSet();
|
||||||
|
IndexFieldData indexFieldData = getForField("value");
|
||||||
|
AtomicReaderContext readerContext = refreshReader();
|
||||||
|
AtomicFieldData fieldData = indexFieldData.load(readerContext);
|
||||||
|
|
||||||
|
assertThat(fieldData.getNumDocs(), equalTo(3));
|
||||||
|
|
||||||
|
BytesValues bytesValues = fieldData.getBytesValues();
|
||||||
|
|
||||||
|
assertThat(bytesValues.isMultiValued(), equalTo(false));
|
||||||
|
|
||||||
|
assertThat(bytesValues.hasValue(0), equalTo(true));
|
||||||
|
assertThat(bytesValues.hasValue(1), equalTo(true));
|
||||||
|
assertThat(bytesValues.hasValue(2), equalTo(true));
|
||||||
|
|
||||||
|
assertThat(bytesValues.getValue(0), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValues.getValue(1), equalTo(new BytesRef(one())));
|
||||||
|
assertThat(bytesValues.getValue(2), equalTo(new BytesRef(three())));
|
||||||
|
|
||||||
|
assertThat(bytesValues.getValueSafe(0), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValues.getValueSafe(1), equalTo(new BytesRef(one())));
|
||||||
|
assertThat(bytesValues.getValueSafe(2), equalTo(new BytesRef(three())));
|
||||||
|
|
||||||
|
BytesRef bytesRef = new BytesRef();
|
||||||
|
assertThat(bytesValues.getValueScratch(0, bytesRef), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesRef, equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValues.getValueScratch(1, bytesRef), equalTo(new BytesRef(one())));
|
||||||
|
assertThat(bytesRef, equalTo(new BytesRef(one())));
|
||||||
|
assertThat(bytesValues.getValueScratch(2, bytesRef), equalTo(new BytesRef(three())));
|
||||||
|
assertThat(bytesRef, equalTo(new BytesRef(three())));
|
||||||
|
|
||||||
|
|
||||||
|
BytesRefArrayRef bytesRefArrayRef = bytesValues.getValues(0);
|
||||||
|
assertThat(bytesRefArrayRef.size(), equalTo(1));
|
||||||
|
assertThat(bytesRefArrayRef.values[bytesRefArrayRef.start], equalTo(new BytesRef(two())));
|
||||||
|
|
||||||
|
bytesRefArrayRef = bytesValues.getValues(1);
|
||||||
|
assertThat(bytesRefArrayRef.size(), equalTo(1));
|
||||||
|
assertThat(bytesRefArrayRef.values[bytesRefArrayRef.start], equalTo(new BytesRef(one())));
|
||||||
|
|
||||||
|
bytesRefArrayRef = bytesValues.getValues(2);
|
||||||
|
assertThat(bytesRefArrayRef.size(), equalTo(1));
|
||||||
|
assertThat(bytesRefArrayRef.values[bytesRefArrayRef.start], equalTo(new BytesRef(three())));
|
||||||
|
|
||||||
|
BytesValues.Iter bytesValuesIter = bytesValues.getIter(0);
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(bytesValuesIter.next(), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
bytesValuesIter = bytesValues.getIterSafe(0);
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(bytesValuesIter.next(), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
bytesValues.forEachValueInDoc(0, new BytesValuesVerifierProc(0).addExpected(two()));
|
||||||
|
bytesValues.forEachValueInDoc(1, new BytesValuesVerifierProc(1).addExpected(one()));
|
||||||
|
bytesValues.forEachValueInDoc(2, new BytesValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
bytesValues.forEachSafeValueInDoc(0, new BytesValuesVerifierProc(0).addExpected(two()));
|
||||||
|
bytesValues.forEachSafeValueInDoc(1, new BytesValuesVerifierProc(1).addExpected(one()));
|
||||||
|
bytesValues.forEachSafeValueInDoc(2, new BytesValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
HashedBytesValues hashedBytesValues = fieldData.getHashedBytesValues();
|
||||||
|
|
||||||
|
assertThat(hashedBytesValues.hasValue(0), equalTo(true));
|
||||||
|
assertThat(hashedBytesValues.hasValue(1), equalTo(true));
|
||||||
|
assertThat(hashedBytesValues.hasValue(2), equalTo(true));
|
||||||
|
|
||||||
|
assertThat(hashedBytesValues.getValue(0), equalTo(new HashedBytesRef(two())));
|
||||||
|
assertThat(hashedBytesValues.getValue(1), equalTo(new HashedBytesRef(one())));
|
||||||
|
assertThat(hashedBytesValues.getValue(2), equalTo(new HashedBytesRef(three())));
|
||||||
|
|
||||||
|
assertThat(hashedBytesValues.getValueSafe(0), equalTo(new HashedBytesRef(two())));
|
||||||
|
assertThat(hashedBytesValues.getValueSafe(1), equalTo(new HashedBytesRef(one())));
|
||||||
|
assertThat(hashedBytesValues.getValueSafe(2), equalTo(new HashedBytesRef(three())));
|
||||||
|
|
||||||
|
HashedBytesValues.Iter hashedBytesValuesIter = hashedBytesValues.getIter(0);
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(hashedBytesValuesIter.next(), equalTo(new HashedBytesRef(two())));
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
hashedBytesValuesIter = hashedBytesValues.getIterSafe(0);
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(hashedBytesValuesIter.next(), equalTo(new HashedBytesRef(two())));
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
hashedBytesValues.forEachValueInDoc(0, new HashedBytesValuesVerifierProc(0).addExpected(two()));
|
||||||
|
hashedBytesValues.forEachValueInDoc(1, new HashedBytesValuesVerifierProc(1).addExpected(one()));
|
||||||
|
hashedBytesValues.forEachValueInDoc(2, new HashedBytesValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
hashedBytesValues.forEachSafeValueInDoc(0, new HashedBytesValuesVerifierProc(0).addExpected(two()));
|
||||||
|
hashedBytesValues.forEachSafeValueInDoc(1, new HashedBytesValuesVerifierProc(1).addExpected(one()));
|
||||||
|
hashedBytesValues.forEachSafeValueInDoc(2, new HashedBytesValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
StringValues stringValues = fieldData.getStringValues();
|
||||||
|
|
||||||
|
assertThat(stringValues.hasValue(0), equalTo(true));
|
||||||
|
assertThat(stringValues.hasValue(1), equalTo(true));
|
||||||
|
assertThat(stringValues.hasValue(2), equalTo(true));
|
||||||
|
|
||||||
|
assertThat(stringValues.getValue(0), equalTo(two()));
|
||||||
|
assertThat(stringValues.getValue(1), equalTo(one()));
|
||||||
|
assertThat(stringValues.getValue(2), equalTo(three()));
|
||||||
|
|
||||||
|
StringArrayRef stringArrayRef;
|
||||||
|
stringArrayRef = stringValues.getValues(0);
|
||||||
|
assertThat(stringArrayRef.size(), equalTo(1));
|
||||||
|
assertThat(stringArrayRef.values[stringArrayRef.start], equalTo(two()));
|
||||||
|
|
||||||
|
stringArrayRef = stringValues.getValues(1);
|
||||||
|
assertThat(stringArrayRef.size(), equalTo(1));
|
||||||
|
assertThat(stringArrayRef.values[stringArrayRef.start], equalTo(one()));
|
||||||
|
|
||||||
|
stringArrayRef = stringValues.getValues(2);
|
||||||
|
assertThat(stringArrayRef.size(), equalTo(1));
|
||||||
|
assertThat(stringArrayRef.values[stringArrayRef.start], equalTo(three()));
|
||||||
|
|
||||||
|
StringValues.Iter stringValuesIter = stringValues.getIter(0);
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(stringValuesIter.next(), equalTo(two()));
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
stringValuesIter = stringValues.getIter(1);
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(stringValuesIter.next(), equalTo(one()));
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
stringValuesIter = stringValues.getIter(2);
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(stringValuesIter.next(), equalTo(three()));
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
stringValues.forEachValueInDoc(0, new StringValuesVerifierProc(0).addExpected(two()));
|
||||||
|
stringValues.forEachValueInDoc(1, new StringValuesVerifierProc(1).addExpected(one()));
|
||||||
|
stringValues.forEachValueInDoc(2, new StringValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
IndexSearcher searcher = new IndexSearcher(readerContext.reader());
|
||||||
|
TopFieldDocs topDocs;
|
||||||
|
|
||||||
|
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||||
|
new Sort(new SortField("value", indexFieldData.comparatorSource(null))));
|
||||||
|
assertThat(topDocs.totalHits, equalTo(3));
|
||||||
|
assertThat(topDocs.scoreDocs[0].doc, equalTo(1));
|
||||||
|
assertThat(topDocs.scoreDocs[1].doc, equalTo(0));
|
||||||
|
assertThat(topDocs.scoreDocs[2].doc, equalTo(2));
|
||||||
|
|
||||||
|
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||||
|
new Sort(new SortField("value", indexFieldData.comparatorSource(null), true)));
|
||||||
|
assertThat(topDocs.totalHits, equalTo(3));
|
||||||
|
assertThat(topDocs.scoreDocs[0].doc, equalTo(2));
|
||||||
|
assertThat(topDocs.scoreDocs[1].doc, equalTo(0));
|
||||||
|
assertThat(topDocs.scoreDocs[2].doc, equalTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fillSingleValueWithMissing() throws Exception {
|
||||||
|
Document d = new Document();
|
||||||
|
d.add(new StringField("_id", "1", Field.Store.NO));
|
||||||
|
d.add(new StringField("value", "2", Field.Store.NO));
|
||||||
|
writer.addDocument(d);
|
||||||
|
|
||||||
|
d = new Document();
|
||||||
|
d.add(new StringField("_id", "2", Field.Store.NO));
|
||||||
|
//d.add(new StringField("value", one(), Field.Store.NO)); // MISSING....
|
||||||
|
writer.addDocument(d);
|
||||||
|
|
||||||
|
d = new Document();
|
||||||
|
d.add(new StringField("_id", "3", Field.Store.NO));
|
||||||
|
d.add(new StringField("value", "3", Field.Store.NO));
|
||||||
|
writer.addDocument(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleValueWithMissing() throws Exception {
|
||||||
|
fillSingleValueWithMissing();
|
||||||
|
IndexFieldData indexFieldData = getForField("value");
|
||||||
|
AtomicFieldData fieldData = indexFieldData.load(refreshReader());
|
||||||
|
|
||||||
|
assertThat(fieldData.getNumDocs(), equalTo(3));
|
||||||
|
|
||||||
|
BytesValues bytesValues = fieldData
|
||||||
|
.getBytesValues();
|
||||||
|
|
||||||
|
assertThat(bytesValues.isMultiValued(), equalTo(false));
|
||||||
|
|
||||||
|
assertThat(bytesValues.hasValue(0), equalTo(true));
|
||||||
|
assertThat(bytesValues.hasValue(1), equalTo(false));
|
||||||
|
assertThat(bytesValues.hasValue(2), equalTo(true));
|
||||||
|
|
||||||
|
assertThat(bytesValues.getValue(0), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValues.getValue(1), nullValue());
|
||||||
|
assertThat(bytesValues.getValue(2), equalTo(new BytesRef(three())));
|
||||||
|
|
||||||
|
assertThat(bytesValues.getValueSafe(0), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValues.getValueSafe(1), nullValue());
|
||||||
|
assertThat(bytesValues.getValueSafe(2), equalTo(new BytesRef(three())));
|
||||||
|
|
||||||
|
BytesRef bytesRef = new BytesRef();
|
||||||
|
assertThat(bytesValues.getValueScratch(0, bytesRef), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesRef, equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValues.getValueScratch(1, bytesRef), equalTo(new BytesRef()));
|
||||||
|
assertThat(bytesRef, equalTo(new BytesRef()));
|
||||||
|
assertThat(bytesValues.getValueScratch(2, bytesRef), equalTo(new BytesRef(three())));
|
||||||
|
assertThat(bytesRef, equalTo(new BytesRef(three())));
|
||||||
|
|
||||||
|
|
||||||
|
BytesRefArrayRef bytesRefArrayRef = bytesValues.getValues(0);
|
||||||
|
assertThat(bytesRefArrayRef.size(), equalTo(1));
|
||||||
|
assertThat(bytesRefArrayRef.values[bytesRefArrayRef.start], equalTo(new BytesRef(two())));
|
||||||
|
|
||||||
|
bytesRefArrayRef = bytesValues.getValues(1);
|
||||||
|
assertThat(bytesRefArrayRef.size(), equalTo(0));
|
||||||
|
|
||||||
|
bytesRefArrayRef = bytesValues.getValues(2);
|
||||||
|
assertThat(bytesRefArrayRef.size(), equalTo(1));
|
||||||
|
assertThat(bytesRefArrayRef.values[bytesRefArrayRef.start], equalTo(new BytesRef(three())));
|
||||||
|
|
||||||
|
BytesValues.Iter bytesValuesIter = bytesValues.getIter(0);
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(bytesValuesIter.next(), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
bytesValuesIter = bytesValues.getIter(1);
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
bytesValuesIter = bytesValues.getIterSafe(0);
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(bytesValuesIter.next(), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
bytesValuesIter = bytesValues.getIterSafe(1);
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
bytesValues.forEachValueInDoc(0, new BytesValuesVerifierProc(0).addExpected(two()));
|
||||||
|
bytesValues.forEachValueInDoc(1, new BytesValuesVerifierProc(1).addMissing());
|
||||||
|
bytesValues.forEachValueInDoc(2, new BytesValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
bytesValues.forEachSafeValueInDoc(0, new BytesValuesVerifierProc(0).addExpected(two()));
|
||||||
|
bytesValues.forEachSafeValueInDoc(1, new BytesValuesVerifierProc(1).addMissing());
|
||||||
|
bytesValues.forEachSafeValueInDoc(2, new BytesValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
HashedBytesValues hashedBytesValues = fieldData.getHashedBytesValues();
|
||||||
|
|
||||||
|
assertThat(hashedBytesValues.hasValue(0), equalTo(true));
|
||||||
|
assertThat(hashedBytesValues.hasValue(1), equalTo(false));
|
||||||
|
assertThat(hashedBytesValues.hasValue(2), equalTo(true));
|
||||||
|
|
||||||
|
assertThat(hashedBytesValues.getValue(0), equalTo(new HashedBytesRef(two())));
|
||||||
|
assertThat(hashedBytesValues.getValue(1), nullValue());
|
||||||
|
assertThat(hashedBytesValues.getValue(2), equalTo(new HashedBytesRef(three())));
|
||||||
|
|
||||||
|
assertThat(hashedBytesValues.getValueSafe(0), equalTo(new HashedBytesRef(two())));
|
||||||
|
assertThat(hashedBytesValues.getValueSafe(1), nullValue());
|
||||||
|
assertThat(hashedBytesValues.getValueSafe(2), equalTo(new HashedBytesRef(three())));
|
||||||
|
|
||||||
|
HashedBytesValues.Iter hashedBytesValuesIter = hashedBytesValues.getIter(0);
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(hashedBytesValuesIter.next(), equalTo(new HashedBytesRef(two())));
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
hashedBytesValuesIter = hashedBytesValues.getIter(1);
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
hashedBytesValuesIter = hashedBytesValues.getIterSafe(0);
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(hashedBytesValuesIter.next(), equalTo(new HashedBytesRef(two())));
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
hashedBytesValuesIter = hashedBytesValues.getIterSafe(1);
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
hashedBytesValues.forEachValueInDoc(0, new HashedBytesValuesVerifierProc(0).addExpected(two()));
|
||||||
|
hashedBytesValues.forEachValueInDoc(1, new HashedBytesValuesVerifierProc(1).addMissing());
|
||||||
|
hashedBytesValues.forEachValueInDoc(2, new HashedBytesValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
hashedBytesValues.forEachSafeValueInDoc(0, new HashedBytesValuesVerifierProc(0).addExpected(two()));
|
||||||
|
hashedBytesValues.forEachSafeValueInDoc(1, new HashedBytesValuesVerifierProc(1).addMissing());
|
||||||
|
hashedBytesValues.forEachSafeValueInDoc(2, new HashedBytesValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
StringValues stringValues = fieldData.getStringValues();
|
||||||
|
|
||||||
|
assertThat(stringValues.hasValue(0), equalTo(true));
|
||||||
|
assertThat(stringValues.hasValue(1), equalTo(false));
|
||||||
|
assertThat(stringValues.hasValue(2), equalTo(true));
|
||||||
|
|
||||||
|
assertThat(stringValues.getValue(0), equalTo(two()));
|
||||||
|
assertThat(stringValues.getValue(1), nullValue());
|
||||||
|
assertThat(stringValues.getValue(2), equalTo(three()));
|
||||||
|
|
||||||
|
StringArrayRef stringArrayRef;
|
||||||
|
stringArrayRef = stringValues.getValues(0);
|
||||||
|
assertThat(stringArrayRef.size(), equalTo(1));
|
||||||
|
assertThat(stringArrayRef.values[stringArrayRef.start], equalTo(two()));
|
||||||
|
|
||||||
|
stringArrayRef = stringValues.getValues(1);
|
||||||
|
assertThat(stringArrayRef.size(), equalTo(0));
|
||||||
|
|
||||||
|
stringArrayRef = stringValues.getValues(2);
|
||||||
|
assertThat(stringArrayRef.size(), equalTo(1));
|
||||||
|
assertThat(stringArrayRef.values[stringArrayRef.start], equalTo(three()));
|
||||||
|
|
||||||
|
StringValues.Iter stringValuesIter = stringValues.getIter(0);
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(stringValuesIter.next(), equalTo(two()));
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
stringValuesIter = stringValues.getIter(1);
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
stringValuesIter = stringValues.getIter(2);
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(stringValuesIter.next(), equalTo(three()));
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
stringValues.forEachValueInDoc(0, new StringValuesVerifierProc(0).addExpected(two()));
|
||||||
|
stringValues.forEachValueInDoc(1, new StringValuesVerifierProc(1).addMissing());
|
||||||
|
stringValues.forEachValueInDoc(2, new StringValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
// TODO properly support missing....
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fillMultiValueAllSet() throws Exception {
|
||||||
|
Document d = new Document();
|
||||||
|
d.add(new StringField("_id", "1", Field.Store.NO));
|
||||||
|
d.add(new StringField("value", "2", Field.Store.NO));
|
||||||
|
d.add(new StringField("value", "4", Field.Store.NO));
|
||||||
|
writer.addDocument(d);
|
||||||
|
|
||||||
|
d = new Document();
|
||||||
|
d.add(new StringField("_id", "2", Field.Store.NO));
|
||||||
|
d.add(new StringField("value", "1", Field.Store.NO));
|
||||||
|
writer.addDocument(d);
|
||||||
|
|
||||||
|
d = new Document();
|
||||||
|
d.add(new StringField("_id", "3", Field.Store.NO));
|
||||||
|
d.add(new StringField("value", "3", Field.Store.NO));
|
||||||
|
writer.addDocument(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultiValueAllSet() throws Exception {
|
||||||
|
fillMultiValueAllSet();
|
||||||
|
IndexFieldData indexFieldData = getForField("value");
|
||||||
|
AtomicFieldData fieldData = indexFieldData.load(refreshReader());
|
||||||
|
|
||||||
|
assertThat(fieldData.getNumDocs(), equalTo(3));
|
||||||
|
|
||||||
|
BytesValues bytesValues = fieldData.getBytesValues();
|
||||||
|
|
||||||
|
assertThat(bytesValues.isMultiValued(), equalTo(true));
|
||||||
|
|
||||||
|
assertThat(bytesValues.hasValue(0), equalTo(true));
|
||||||
|
assertThat(bytesValues.hasValue(1), equalTo(true));
|
||||||
|
assertThat(bytesValues.hasValue(2), equalTo(true));
|
||||||
|
|
||||||
|
assertThat(bytesValues.getValue(0), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValues.getValue(1), equalTo(new BytesRef(one())));
|
||||||
|
assertThat(bytesValues.getValue(2), equalTo(new BytesRef(three())));
|
||||||
|
|
||||||
|
assertThat(bytesValues.getValueSafe(0), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValues.getValueSafe(1), equalTo(new BytesRef(one())));
|
||||||
|
assertThat(bytesValues.getValueSafe(2), equalTo(new BytesRef(three())));
|
||||||
|
|
||||||
|
BytesRef bytesRef = new BytesRef();
|
||||||
|
assertThat(bytesValues.getValueScratch(0, bytesRef), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesRef, equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValues.getValueScratch(1, bytesRef), equalTo(new BytesRef(one())));
|
||||||
|
assertThat(bytesRef, equalTo(new BytesRef(one())));
|
||||||
|
assertThat(bytesValues.getValueScratch(2, bytesRef), equalTo(new BytesRef(three())));
|
||||||
|
assertThat(bytesRef, equalTo(new BytesRef(three())));
|
||||||
|
|
||||||
|
|
||||||
|
BytesRefArrayRef bytesRefArrayRef = bytesValues.getValues(0);
|
||||||
|
assertThat(bytesRefArrayRef.size(), equalTo(2));
|
||||||
|
assertThat(bytesRefArrayRef.values[bytesRefArrayRef.start], equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesRefArrayRef.values[bytesRefArrayRef.start + 1], equalTo(new BytesRef(four())));
|
||||||
|
|
||||||
|
bytesRefArrayRef = bytesValues.getValues(1);
|
||||||
|
assertThat(bytesRefArrayRef.size(), equalTo(1));
|
||||||
|
assertThat(bytesRefArrayRef.values[bytesRefArrayRef.start], equalTo(new BytesRef(one())));
|
||||||
|
|
||||||
|
bytesRefArrayRef = bytesValues.getValues(2);
|
||||||
|
assertThat(bytesRefArrayRef.size(), equalTo(1));
|
||||||
|
assertThat(bytesRefArrayRef.values[bytesRefArrayRef.start], equalTo(new BytesRef(three())));
|
||||||
|
|
||||||
|
BytesValues.Iter bytesValuesIter = bytesValues.getIter(0);
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(bytesValuesIter.next(), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(bytesValuesIter.next(), equalTo(new BytesRef(four())));
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
bytesValuesIter = bytesValues.getIterSafe(0);
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(bytesValuesIter.next(), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(bytesValuesIter.next(), equalTo(new BytesRef(four())));
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
bytesValues.forEachValueInDoc(0, new BytesValuesVerifierProc(0).addExpected(two()).addExpected(four()));
|
||||||
|
bytesValues.forEachValueInDoc(1, new BytesValuesVerifierProc(1).addExpected(one()));
|
||||||
|
bytesValues.forEachValueInDoc(2, new BytesValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
bytesValues.forEachSafeValueInDoc(0, new BytesValuesVerifierProc(0).addExpected(two()).addExpected(four()));
|
||||||
|
bytesValues.forEachSafeValueInDoc(1, new BytesValuesVerifierProc(1).addExpected(one()));
|
||||||
|
bytesValues.forEachSafeValueInDoc(2, new BytesValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
HashedBytesValues hashedBytesValues = fieldData.getHashedBytesValues();
|
||||||
|
|
||||||
|
assertThat(hashedBytesValues.hasValue(0), equalTo(true));
|
||||||
|
assertThat(hashedBytesValues.hasValue(1), equalTo(true));
|
||||||
|
assertThat(hashedBytesValues.hasValue(2), equalTo(true));
|
||||||
|
|
||||||
|
assertThat(hashedBytesValues.getValue(0), equalTo(new HashedBytesRef(two())));
|
||||||
|
assertThat(hashedBytesValues.getValue(1), equalTo(new HashedBytesRef(one())));
|
||||||
|
assertThat(hashedBytesValues.getValue(2), equalTo(new HashedBytesRef(three())));
|
||||||
|
|
||||||
|
assertThat(hashedBytesValues.getValueSafe(0), equalTo(new HashedBytesRef(two())));
|
||||||
|
assertThat(hashedBytesValues.getValueSafe(1), equalTo(new HashedBytesRef(one())));
|
||||||
|
assertThat(hashedBytesValues.getValueSafe(2), equalTo(new HashedBytesRef(three())));
|
||||||
|
|
||||||
|
HashedBytesValues.Iter hashedBytesValuesIter = hashedBytesValues.getIter(0);
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(hashedBytesValuesIter.next(), equalTo(new HashedBytesRef(two())));
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(hashedBytesValuesIter.next(), equalTo(new HashedBytesRef(four())));
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
hashedBytesValuesIter = hashedBytesValues.getIterSafe(0);
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(hashedBytesValuesIter.next(), equalTo(new HashedBytesRef(two())));
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(hashedBytesValuesIter.next(), equalTo(new HashedBytesRef(four())));
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
hashedBytesValues.forEachValueInDoc(0, new HashedBytesValuesVerifierProc(0).addExpected(two()).addExpected(four()));
|
||||||
|
hashedBytesValues.forEachValueInDoc(1, new HashedBytesValuesVerifierProc(1).addExpected(one()));
|
||||||
|
hashedBytesValues.forEachValueInDoc(2, new HashedBytesValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
hashedBytesValues.forEachSafeValueInDoc(0, new HashedBytesValuesVerifierProc(0).addExpected(two()).addExpected(four()));
|
||||||
|
hashedBytesValues.forEachSafeValueInDoc(1, new HashedBytesValuesVerifierProc(1).addExpected(one()));
|
||||||
|
hashedBytesValues.forEachSafeValueInDoc(2, new HashedBytesValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
StringValues stringValues = fieldData.getStringValues();
|
||||||
|
|
||||||
|
assertThat(stringValues.hasValue(0), equalTo(true));
|
||||||
|
assertThat(stringValues.hasValue(1), equalTo(true));
|
||||||
|
assertThat(stringValues.hasValue(2), equalTo(true));
|
||||||
|
|
||||||
|
assertThat(stringValues.getValue(0), equalTo(two()));
|
||||||
|
assertThat(stringValues.getValue(1), equalTo(one()));
|
||||||
|
assertThat(stringValues.getValue(2), equalTo(three()));
|
||||||
|
|
||||||
|
StringArrayRef stringArrayRef;
|
||||||
|
stringArrayRef = stringValues.getValues(0);
|
||||||
|
assertThat(stringArrayRef.size(), equalTo(2));
|
||||||
|
assertThat(stringArrayRef.values[stringArrayRef.start], equalTo(two()));
|
||||||
|
assertThat(stringArrayRef.values[stringArrayRef.start + 1], equalTo(four()));
|
||||||
|
|
||||||
|
stringArrayRef = stringValues.getValues(1);
|
||||||
|
assertThat(stringArrayRef.size(), equalTo(1));
|
||||||
|
assertThat(stringArrayRef.values[stringArrayRef.start], equalTo(one()));
|
||||||
|
|
||||||
|
stringArrayRef = stringValues.getValues(2);
|
||||||
|
assertThat(stringArrayRef.size(), equalTo(1));
|
||||||
|
assertThat(stringArrayRef.values[stringArrayRef.start], equalTo(three()));
|
||||||
|
|
||||||
|
StringValues.Iter stringValuesIter = stringValues.getIter(0);
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(stringValuesIter.next(), equalTo(two()));
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(stringValuesIter.next(), equalTo(four()));
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
stringValuesIter = stringValues.getIter(1);
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(stringValuesIter.next(), equalTo(one()));
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
stringValuesIter = stringValues.getIter(2);
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(stringValuesIter.next(), equalTo(three()));
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
stringValues.forEachValueInDoc(0, new StringValuesVerifierProc(0).addExpected(two()).addExpected(four()));
|
||||||
|
stringValues.forEachValueInDoc(1, new StringValuesVerifierProc(1).addExpected(one()));
|
||||||
|
stringValues.forEachValueInDoc(2, new StringValuesVerifierProc(2).addExpected(three()));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fillMultiValueWithMissing() throws Exception {
|
||||||
|
Document d = new Document();
|
||||||
|
d.add(new StringField("_id", "1", Field.Store.NO));
|
||||||
|
d.add(new StringField("value", "2", Field.Store.NO));
|
||||||
|
d.add(new StringField("value", "4", Field.Store.NO));
|
||||||
|
writer.addDocument(d);
|
||||||
|
|
||||||
|
d = new Document();
|
||||||
|
d.add(new StringField("_id", "2", Field.Store.NO));
|
||||||
|
//d.add(new StringField("value", one(), Field.Store.NO)); // MISSING
|
||||||
|
writer.addDocument(d);
|
||||||
|
|
||||||
|
d = new Document();
|
||||||
|
d.add(new StringField("_id", "3", Field.Store.NO));
|
||||||
|
d.add(new StringField("value", "3", Field.Store.NO));
|
||||||
|
writer.addDocument(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultiValueWithMissing() throws Exception {
|
||||||
|
fillMultiValueWithMissing();
|
||||||
|
IndexFieldData indexFieldData = getForField("value");
|
||||||
|
AtomicFieldData fieldData = indexFieldData.load(refreshReader());
|
||||||
|
|
||||||
|
assertThat(fieldData.getNumDocs(), equalTo(3));
|
||||||
|
|
||||||
|
BytesValues bytesValues = fieldData.getBytesValues();
|
||||||
|
|
||||||
|
assertThat(bytesValues.isMultiValued(), equalTo(true));
|
||||||
|
|
||||||
|
assertThat(bytesValues.hasValue(0), equalTo(true));
|
||||||
|
assertThat(bytesValues.hasValue(1), equalTo(false));
|
||||||
|
assertThat(bytesValues.hasValue(2), equalTo(true));
|
||||||
|
|
||||||
|
assertThat(bytesValues.getValue(0), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValues.getValue(1), nullValue());
|
||||||
|
assertThat(bytesValues.getValue(2), equalTo(new BytesRef(three())));
|
||||||
|
|
||||||
|
assertThat(bytesValues.getValueSafe(0), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValues.getValueSafe(1), nullValue());
|
||||||
|
assertThat(bytesValues.getValueSafe(2), equalTo(new BytesRef(three())));
|
||||||
|
|
||||||
|
BytesRef bytesRef = new BytesRef();
|
||||||
|
assertThat(bytesValues.getValueScratch(0, bytesRef), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesRef, equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValues.getValueScratch(1, bytesRef), equalTo(new BytesRef()));
|
||||||
|
assertThat(bytesRef, equalTo(new BytesRef()));
|
||||||
|
assertThat(bytesValues.getValueScratch(2, bytesRef), equalTo(new BytesRef(three())));
|
||||||
|
assertThat(bytesRef, equalTo(new BytesRef(three())));
|
||||||
|
|
||||||
|
|
||||||
|
BytesRefArrayRef bytesRefArrayRef = bytesValues.getValues(0);
|
||||||
|
assertThat(bytesRefArrayRef.size(), equalTo(2));
|
||||||
|
assertThat(bytesRefArrayRef.values[bytesRefArrayRef.start], equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesRefArrayRef.values[bytesRefArrayRef.start + 1], equalTo(new BytesRef(four())));
|
||||||
|
|
||||||
|
bytesRefArrayRef = bytesValues.getValues(1);
|
||||||
|
assertThat(bytesRefArrayRef.size(), equalTo(0));
|
||||||
|
|
||||||
|
bytesRefArrayRef = bytesValues.getValues(2);
|
||||||
|
assertThat(bytesRefArrayRef.size(), equalTo(1));
|
||||||
|
assertThat(bytesRefArrayRef.values[bytesRefArrayRef.start], equalTo(new BytesRef(three())));
|
||||||
|
|
||||||
|
BytesValues.Iter bytesValuesIter = bytesValues.getIter(0);
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(bytesValuesIter.next(), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(bytesValuesIter.next(), equalTo(new BytesRef(four())));
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
bytesValuesIter = bytesValues.getIter(1);
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
bytesValuesIter = bytesValues.getIterSafe(0);
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(bytesValuesIter.next(), equalTo(new BytesRef(two())));
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(bytesValuesIter.next(), equalTo(new BytesRef(four())));
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
bytesValuesIter = bytesValues.getIterSafe(1);
|
||||||
|
assertThat(bytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
bytesValues.forEachValueInDoc(0, new BytesValuesVerifierProc(0).addExpected(two()).addExpected(four()));
|
||||||
|
bytesValues.forEachValueInDoc(1, new BytesValuesVerifierProc(1).addMissing());
|
||||||
|
bytesValues.forEachValueInDoc(2, new BytesValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
bytesValues.forEachSafeValueInDoc(0, new BytesValuesVerifierProc(0).addExpected(two()).addExpected(four()));
|
||||||
|
bytesValues.forEachSafeValueInDoc(1, new BytesValuesVerifierProc(1).addMissing());
|
||||||
|
bytesValues.forEachSafeValueInDoc(2, new BytesValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
HashedBytesValues hashedBytesValues = fieldData.getHashedBytesValues();
|
||||||
|
|
||||||
|
assertThat(hashedBytesValues.hasValue(0), equalTo(true));
|
||||||
|
assertThat(hashedBytesValues.hasValue(1), equalTo(false));
|
||||||
|
assertThat(hashedBytesValues.hasValue(2), equalTo(true));
|
||||||
|
|
||||||
|
assertThat(hashedBytesValues.getValue(0), equalTo(new HashedBytesRef(two())));
|
||||||
|
assertThat(hashedBytesValues.getValue(1), nullValue());
|
||||||
|
assertThat(hashedBytesValues.getValue(2), equalTo(new HashedBytesRef(three())));
|
||||||
|
|
||||||
|
assertThat(hashedBytesValues.getValueSafe(0), equalTo(new HashedBytesRef(two())));
|
||||||
|
assertThat(hashedBytesValues.getValueSafe(1), nullValue());
|
||||||
|
assertThat(hashedBytesValues.getValueSafe(2), equalTo(new HashedBytesRef(three())));
|
||||||
|
|
||||||
|
HashedBytesValues.Iter hashedBytesValuesIter = hashedBytesValues.getIter(0);
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(hashedBytesValuesIter.next(), equalTo(new HashedBytesRef(two())));
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(hashedBytesValuesIter.next(), equalTo(new HashedBytesRef(four())));
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
hashedBytesValuesIter = hashedBytesValues.getIter(1);
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
hashedBytesValuesIter = hashedBytesValues.getIterSafe(0);
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(hashedBytesValuesIter.next(), equalTo(new HashedBytesRef(two())));
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(hashedBytesValuesIter.next(), equalTo(new HashedBytesRef(four())));
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
hashedBytesValuesIter = hashedBytesValues.getIterSafe(1);
|
||||||
|
assertThat(hashedBytesValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
hashedBytesValues.forEachValueInDoc(0, new HashedBytesValuesVerifierProc(0).addExpected(two()).addExpected(four()));
|
||||||
|
hashedBytesValues.forEachValueInDoc(1, new HashedBytesValuesVerifierProc(1).addMissing());
|
||||||
|
hashedBytesValues.forEachValueInDoc(2, new HashedBytesValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
hashedBytesValues.forEachSafeValueInDoc(0, new HashedBytesValuesVerifierProc(0).addExpected(two()).addExpected(four()));
|
||||||
|
hashedBytesValues.forEachSafeValueInDoc(1, new HashedBytesValuesVerifierProc(1).addMissing());
|
||||||
|
hashedBytesValues.forEachSafeValueInDoc(2, new HashedBytesValuesVerifierProc(2).addExpected(three()));
|
||||||
|
|
||||||
|
StringValues stringValues = fieldData.getStringValues();
|
||||||
|
|
||||||
|
assertThat(stringValues.hasValue(0), equalTo(true));
|
||||||
|
assertThat(stringValues.hasValue(1), equalTo(false));
|
||||||
|
assertThat(stringValues.hasValue(2), equalTo(true));
|
||||||
|
|
||||||
|
assertThat(stringValues.getValue(0), equalTo(two()));
|
||||||
|
assertThat(stringValues.getValue(1), nullValue());
|
||||||
|
assertThat(stringValues.getValue(2), equalTo(three()));
|
||||||
|
|
||||||
|
StringArrayRef stringArrayRef;
|
||||||
|
stringArrayRef = stringValues.getValues(0);
|
||||||
|
assertThat(stringArrayRef.size(), equalTo(2));
|
||||||
|
assertThat(stringArrayRef.values[stringArrayRef.start], equalTo(two()));
|
||||||
|
assertThat(stringArrayRef.values[stringArrayRef.start + 1], equalTo(four()));
|
||||||
|
|
||||||
|
stringArrayRef = stringValues.getValues(1);
|
||||||
|
assertThat(stringArrayRef.size(), equalTo(0));
|
||||||
|
|
||||||
|
stringArrayRef = stringValues.getValues(2);
|
||||||
|
assertThat(stringArrayRef.size(), equalTo(1));
|
||||||
|
assertThat(stringArrayRef.values[stringArrayRef.start], equalTo(three()));
|
||||||
|
|
||||||
|
StringValues.Iter stringValuesIter = stringValues.getIter(0);
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(stringValuesIter.next(), equalTo(two()));
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(stringValuesIter.next(), equalTo(four()));
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
stringValuesIter = stringValues.getIter(1);
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
stringValuesIter = stringValues.getIter(2);
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(true));
|
||||||
|
assertThat(stringValuesIter.next(), equalTo(three()));
|
||||||
|
assertThat(stringValuesIter.hasNext(), equalTo(false));
|
||||||
|
|
||||||
|
stringValues.forEachValueInDoc(0, new StringValuesVerifierProc(0).addExpected(two()).addExpected(four()));
|
||||||
|
stringValues.forEachValueInDoc(1, new StringValuesVerifierProc(1).addMissing());
|
||||||
|
stringValues.forEachValueInDoc(2, new StringValuesVerifierProc(2).addExpected(three()));
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user