|
@@ -19,18 +19,25 @@
|
|
|
|
|
|
package org.elasticsearch.index.mapper.core;
|
|
|
|
|
|
+import com.carrotsearch.hppc.ObjectArrayList;
|
|
|
import org.apache.lucene.document.Field;
|
|
|
import org.apache.lucene.document.FieldType;
|
|
|
+import org.apache.lucene.index.FieldInfo;
|
|
|
+import org.apache.lucene.store.ByteArrayDataOutput;
|
|
|
import org.apache.lucene.util.BytesRef;
|
|
|
+import org.elasticsearch.ElasticsearchException;
|
|
|
import org.elasticsearch.ElasticsearchParseException;
|
|
|
import org.elasticsearch.common.Base64;
|
|
|
+import org.elasticsearch.common.Nullable;
|
|
|
import org.elasticsearch.common.Strings;
|
|
|
import org.elasticsearch.common.bytes.BytesArray;
|
|
|
import org.elasticsearch.common.bytes.BytesReference;
|
|
|
import org.elasticsearch.common.compress.CompressorFactory;
|
|
|
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
|
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
|
|
+import org.elasticsearch.common.settings.Settings;
|
|
|
import org.elasticsearch.common.unit.ByteSizeValue;
|
|
|
+import org.elasticsearch.common.util.CollectionUtils;
|
|
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
|
|
import org.elasticsearch.common.xcontent.XContentParser;
|
|
|
import org.elasticsearch.index.codec.docvaluesformat.DocValuesFormatProvider;
|
|
@@ -86,8 +93,8 @@ public class BinaryFieldMapper extends AbstractFieldMapper<BytesReference> {
|
|
|
|
|
|
@Override
|
|
|
public BinaryFieldMapper build(BuilderContext context) {
|
|
|
- return new BinaryFieldMapper(buildNames(context), fieldType, compress, compressThreshold, postingsProvider,
|
|
|
- docValuesProvider, multiFieldsBuilder.build(this, context), copyTo);
|
|
|
+ return new BinaryFieldMapper(buildNames(context), fieldType, docValues, compress, compressThreshold, postingsProvider,
|
|
|
+ docValuesProvider, fieldDataSettings, multiFieldsBuilder.build(this, context), copyTo);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -119,10 +126,10 @@ public class BinaryFieldMapper extends AbstractFieldMapper<BytesReference> {
|
|
|
|
|
|
private long compressThreshold;
|
|
|
|
|
|
- protected BinaryFieldMapper(Names names, FieldType fieldType, Boolean compress, long compressThreshold,
|
|
|
- PostingsFormatProvider postingsProvider, DocValuesFormatProvider docValuesProvider,
|
|
|
+ protected BinaryFieldMapper(Names names, FieldType fieldType, Boolean docValues, Boolean compress, long compressThreshold,
|
|
|
+ PostingsFormatProvider postingsProvider, DocValuesFormatProvider docValuesProvider, @Nullable Settings fieldDataSettings,
|
|
|
MultiFields multiFields, CopyTo copyTo) {
|
|
|
- super(names, 1.0f, fieldType, null, null, null, postingsProvider, docValuesProvider, null, null, null, null, multiFields, copyTo);
|
|
|
+ super(names, 1.0f, fieldType, docValues, null, null, postingsProvider, docValuesProvider, null, null, fieldDataSettings, null, multiFields, copyTo);
|
|
|
this.compress = compress;
|
|
|
this.compressThreshold = compressThreshold;
|
|
|
}
|
|
@@ -134,7 +141,7 @@ public class BinaryFieldMapper extends AbstractFieldMapper<BytesReference> {
|
|
|
|
|
|
@Override
|
|
|
public FieldDataType defaultFieldDataType() {
|
|
|
- return null;
|
|
|
+ return new FieldDataType("binary");
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -171,7 +178,7 @@ public class BinaryFieldMapper extends AbstractFieldMapper<BytesReference> {
|
|
|
|
|
|
@Override
|
|
|
protected void parseCreateField(ParseContext context, List<Field> fields) throws IOException {
|
|
|
- if (!fieldType().stored()) {
|
|
|
+ if (!fieldType().stored() && !hasDocValues()) {
|
|
|
return;
|
|
|
}
|
|
|
byte[] value = context.parseExternalValue(byte[].class);
|
|
@@ -194,7 +201,20 @@ public class BinaryFieldMapper extends AbstractFieldMapper<BytesReference> {
|
|
|
value = bStream.bytes().toBytes();
|
|
|
}
|
|
|
}
|
|
|
- fields.add(new Field(names.indexName(), value, fieldType));
|
|
|
+ if (fieldType().stored()) {
|
|
|
+ fields.add(new Field(names.indexName(), value, fieldType));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hasDocValues()) {
|
|
|
+ CustomBinaryDocValuesField field = (CustomBinaryDocValuesField) context.doc().getByKey(names().indexName());
|
|
|
+ if (field == null) {
|
|
|
+ field = new CustomBinaryDocValuesField(names().indexName(), value);
|
|
|
+ context.doc().addWithKey(names().indexName(), field);
|
|
|
+ } else {
|
|
|
+ field.add(value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -204,10 +224,7 @@ public class BinaryFieldMapper extends AbstractFieldMapper<BytesReference> {
|
|
|
|
|
|
@Override
|
|
|
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
|
|
|
- builder.field("type", contentType());
|
|
|
- if (includeDefaults || !names.name().equals(names.indexNameClean())) {
|
|
|
- builder.field("index_name", names.indexNameClean());
|
|
|
- }
|
|
|
+ super.doXContentBody(builder, includeDefaults, params);
|
|
|
if (compress != null) {
|
|
|
builder.field("compress", compress);
|
|
|
} else if (includeDefaults) {
|
|
@@ -218,32 +235,16 @@ public class BinaryFieldMapper extends AbstractFieldMapper<BytesReference> {
|
|
|
} else if (includeDefaults) {
|
|
|
builder.field("compress_threshold", -1);
|
|
|
}
|
|
|
- if (includeDefaults || fieldType.stored() != defaultFieldType().stored()) {
|
|
|
- builder.field("store", fieldType.stored());
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void merge(Mapper mergeWith, MergeContext mergeContext) throws MergeMappingException {
|
|
|
- if (!(mergeWith instanceof BinaryFieldMapper)) {
|
|
|
- String mergedType = mergeWith.getClass().getSimpleName();
|
|
|
- if (mergeWith instanceof AbstractFieldMapper) {
|
|
|
- mergedType = ((AbstractFieldMapper) mergeWith).contentType();
|
|
|
- }
|
|
|
- mergeContext.addConflict("mapper [" + names.fullName() + "] of different type, current_type [" + contentType() + "], merged_type [" + mergedType + "]");
|
|
|
- // different types, return
|
|
|
+ super.merge(mergeWith, mergeContext);
|
|
|
+ if (!this.getClass().equals(mergeWith.getClass())) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
BinaryFieldMapper sourceMergeWith = (BinaryFieldMapper) mergeWith;
|
|
|
-
|
|
|
- if (this.fieldType().stored() != sourceMergeWith.fieldType().stored()) {
|
|
|
- mergeContext.addConflict("mapper [" + names.fullName() + "] has different store values");
|
|
|
- }
|
|
|
- if (!this.names().equals(sourceMergeWith.names())) {
|
|
|
- mergeContext.addConflict("mapper [" + names.fullName() + "] has different index_name");
|
|
|
- }
|
|
|
-
|
|
|
if (!mergeContext.mergeFlags().simulate()) {
|
|
|
if (sourceMergeWith.compress != null) {
|
|
|
this.compress = sourceMergeWith.compress;
|
|
@@ -254,8 +255,48 @@ public class BinaryFieldMapper extends AbstractFieldMapper<BytesReference> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public boolean hasDocValues() {
|
|
|
- return false;
|
|
|
+ public static class CustomBinaryDocValuesField extends NumberFieldMapper.CustomNumericDocValuesField {
|
|
|
+
|
|
|
+ public static final FieldType TYPE = new FieldType();
|
|
|
+ static {
|
|
|
+ TYPE.setDocValueType(FieldInfo.DocValuesType.BINARY);
|
|
|
+ TYPE.freeze();
|
|
|
+ }
|
|
|
+
|
|
|
+ private final ObjectArrayList<byte[]> bytesList;
|
|
|
+
|
|
|
+ private int totalSize = 0;
|
|
|
+
|
|
|
+ public CustomBinaryDocValuesField(String name, byte[] bytes) {
|
|
|
+ super(name);
|
|
|
+ bytesList = new ObjectArrayList<>();
|
|
|
+ add(bytes);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void add(byte[] bytes) {
|
|
|
+ bytesList.add(bytes);
|
|
|
+ totalSize += bytes.length;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public BytesRef binaryValue() {
|
|
|
+ try {
|
|
|
+ CollectionUtils.sortAndDedup(bytesList);
|
|
|
+ int size = bytesList.size();
|
|
|
+ final byte[] bytes = new byte[totalSize + (size + 1) * 5];
|
|
|
+ ByteArrayDataOutput out = new ByteArrayDataOutput(bytes);
|
|
|
+ out.writeVInt(size); // write total number of values
|
|
|
+ for (int i = 0; i < size; i ++) {
|
|
|
+ final byte[] value = bytesList.get(i);
|
|
|
+ int valueLength = value.length;
|
|
|
+ out.writeVInt(valueLength);
|
|
|
+ out.writeBytes(value, 0, valueLength);
|
|
|
+ }
|
|
|
+ return new BytesRef(bytes, 0, out.getPosition());
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new ElasticsearchException("Failed to get binary value", e);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
}
|
|
|
}
|