Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BinaryDocValuesField to replace BytesRef (ScriptDocValues) #79760

Merged
merged 19 commits into from
Oct 29, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ class org.elasticsearch.script.DocBasedScript {
}

class org.elasticsearch.script.field.DelegateDocValuesField @dynamic_type {
def getValue(def)
List getValues()
def getValue(def)
jdconrad marked this conversation as resolved.
Show resolved Hide resolved
def getValue(int, def)
}

class org.elasticsearch.script.field.BinaryDocValuesField @dynamic_type {
List getValues()
BytesRef getValue(BytesRef)
stu-elastic marked this conversation as resolved.
Show resolved Hide resolved
BytesRef getValue(int, BytesRef)
stu-elastic marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,20 @@
source: "doc['binary'].value.utf8ToString()"
- match: { hits.hits.0.fields.field1.0: "Some binary blob" }
- match: { hits.hits.0.fields.field2.0: "Some binary blob" }

- do:
search:
body:
script_fields:
field1:
script:
source: "field('binary').getValue(null).utf8ToString()"
field2:
script:
source: "field('binary').getValue(0, null).utf8ToString()"
field3:
script:
source: "field('binary').getValues()[0].utf8ToString()"
- match: { hits.hits.0.fields.field1.0: "Some binary blob" }
- match: { hits.hits.0.fields.field2.0: "Some binary blob" }
- match: { hits.hits.0.fields.field3.0: "Some binary blob" }
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.elasticsearch.common.geo.GeoUtils;
import org.elasticsearch.common.time.DateUtils;
import org.elasticsearch.geometry.utils.Geohash;
import org.elasticsearch.script.field.BinaryDocValuesField;

import java.io.IOException;
import java.time.Instant;
Expand Down Expand Up @@ -573,28 +574,33 @@ public final String getValue() {
}
}

public static final class BytesRefs extends BinaryScriptDocValues<BytesRef> {
public static final class BytesRefs extends ScriptDocValues<BytesRef> {

public BytesRefs(SortedBinaryDocValues in) {
super(in);
private final BinaryDocValuesField binaryDocValuesField;

public BytesRefs(BinaryDocValuesField binaryDocValuesField) {
this.binaryDocValuesField = binaryDocValuesField;
}

@Override
public BytesRef get(int index) {
if (count == 0) {
throw new IllegalStateException("A document doesn't have a value for a field! " +
"Use doc[<field>].size()==0 to check if a document is missing a field!");
}
/**
* We need to make a copy here because {@link BinaryScriptDocValues} might reuse the
* returned value and the same instance might be used to
* return values from multiple documents.
**/
return values[index].toBytesRef();
public void setNextDocId(int docId) throws IOException {
throw new UnsupportedOperationException();
jdconrad marked this conversation as resolved.
Show resolved Hide resolved
}

public BytesRef getValue() {
return get(0);
throwIfEmpty();
return binaryDocValuesField.getValue(null); // default is ignored
jdconrad marked this conversation as resolved.
Show resolved Hide resolved
}

@Override
public BytesRef get(int index) {
throwIfEmpty();
return binaryDocValuesField.getValue(null); // default is ignored
}

@Override
public int size() {
return binaryDocValuesField.size();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
package org.elasticsearch.index.fielddata.plain;

import org.apache.lucene.index.BinaryDocValues;
import org.elasticsearch.index.fielddata.ScriptDocValues;
import org.elasticsearch.script.field.DelegateDocValuesField;
import org.elasticsearch.script.field.BinaryDocValuesField;
import org.elasticsearch.script.field.DocValuesField;


Expand All @@ -21,7 +20,7 @@ final class BytesBinaryDVLeafFieldData extends AbstractBinaryDVLeafFieldData {

@Override
public DocValuesField getScriptField(String name) {
return new DelegateDocValuesField(new ScriptDocValues.BytesRefs(getBytesValues()), name);
return new BinaryDocValuesField(getBytesValues(), name);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

package org.elasticsearch.script.field;

import org.apache.lucene.util.ArrayUtil;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefBuilder;
import org.elasticsearch.index.fielddata.ScriptDocValues;
import org.elasticsearch.index.fielddata.ScriptDocValues.BytesRefs;
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class BinaryDocValuesField implements DocValuesField {

private final SortedBinaryDocValues input;
private final String name;
jdconrad marked this conversation as resolved.
Show resolved Hide resolved

private BytesRefBuilder[] values = new BytesRefBuilder[0];
private int count;

// used for backwards compatibility for old-style "doc" access
// as a delegate to this field class
private BytesRefs bytesRefs = null;

public BinaryDocValuesField(SortedBinaryDocValues input, String name) {
this.input = input;
this.name = name;
}

@Override
public void setNextDocId(int docId) throws IOException {
if (input.advanceExact(docId)) {
resize(input.docValueCount());
for (int i = 0; i < count; i++) {
// We need to make a copy here, because BytesBinaryDVLeafFieldData's SortedBinaryDocValues
// implementation reuses the returned BytesRef. Otherwise, we would end up with the same BytesRef
// instance for all slots in the values array.
values[i].copyBytes(input.nextValue());
}
} else {
resize(0);
}
}

private void resize(int newSize) {
count = newSize;

if (newSize > values.length) {
int oldLength = values.length;
values = ArrayUtil.grow(values, count);

for (int i = oldLength; i < values.length; ++i) {
values[i] = new BytesRefBuilder();
}
}
}

@Override
public ScriptDocValues<?> getScriptDocValues() {
if (bytesRefs == null) {
bytesRefs = new BytesRefs(this);
}

return bytesRefs;
}

@Override
public String getName() {
return name;
}

@Override
public boolean isEmpty() {
return count == 0;
}

@Override
public int size() {
return count;
}

public List<BytesRef> getValues() {
if (isEmpty()) {
return Collections.emptyList();
}

List<BytesRef> values = new ArrayList<>(count);

for (int index = 0; index < count; ++index) {
values.add(this.values[index].toBytesRef());
}

return values;
}

public BytesRef getValue(BytesRef defaultValue) {
return getValue(0, defaultValue);
}

public BytesRef getValue(int index, BytesRef defaultValue) {
if (isEmpty() || index < 0 || index >= count) {
return defaultValue;
}

return values[index].toBytesRef();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,15 @@ public int size() {
throw new UnsupportedOperationException("field [" + name + "] is not supported through the fields api, use [doc] instead");
}

public List<?> getValues() {
throw new UnsupportedOperationException("field [" + name + "] is not supported through the fields api, use [doc] instead");
jdconrad marked this conversation as resolved.
Show resolved Hide resolved
}

public Object getValue(Object defaultValue) {
throw new UnsupportedOperationException("field [" + name + "] is not supported through the fields api, use [doc] instead");
}

public List<?> getValues() {
public Object getValue(int index, Object defaultValue) {
throw new UnsupportedOperationException("field [" + name + "] is not supported through the fields api, use [doc] instead");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.script.field.BinaryDocValuesField;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xcontent.XContentFactory;
import org.elasticsearch.xcontent.XContentType;
Expand Down Expand Up @@ -109,15 +110,15 @@ public void testDocValue() throws Exception {
assertEquals(bytesList2.get(0), bytesValues.nextValue());
assertEquals(bytesList2.get(1), bytesValues.nextValue());

// Test whether ScriptDocValues.BytesRefs makes a deepcopy
// Test whether BinaryDocValuesField makes a deepcopy
fieldData = indexFieldData.load(reader);
ScriptDocValues<?> scriptValues = fieldData.getScriptField("test").getScriptDocValues();
BinaryDocValuesField binaryDocValuesField = (BinaryDocValuesField)fieldData.getScriptField("test");
Object[][] retValues = new BytesRef[4][0];
for (int i = 0; i < 4; i++) {
scriptValues.setNextDocId(i);
retValues[i] = new BytesRef[scriptValues.size()];
binaryDocValuesField.setNextDocId(i);
retValues[i] = new BytesRef[binaryDocValuesField.size()];
for (int j = 0; j < retValues[i].length; j++) {
retValues[i][j] = scriptValues.get(j);
retValues[i][j] = binaryDocValuesField.getValue(j, null);
}
}
assertEquals(2, retValues[0].length);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public void setNextDocId(int docId) throws IOException {
}
}

private void resize(int newSize) {
jdconrad marked this conversation as resolved.
Show resolved Hide resolved
count = newSize;
values = ArrayUtil.grow(values, count);
}

@Override
public ScriptDocValues<?> getScriptDocValues() {
if (unsignedLongScriptDocValues == null) {
Expand All @@ -59,11 +64,6 @@ public ScriptDocValues<?> getScriptDocValues() {
return unsignedLongScriptDocValues;
}

protected void resize(int newSize) {
count = newSize;
values = ArrayUtil.grow(values, count);
}

@Override
public String getName() {
return name;
Expand Down