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

Search: Simply SingleFieldsVisitor #34052

Merged
merged 3 commits into from
Sep 26, 2018
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -19,42 +19,79 @@
package org.elasticsearch.index.fieldvisitor;

import org.apache.lucene.index.FieldInfo;
import org.apache.lucene.index.StoredFieldVisitor;
import org.elasticsearch.index.mapper.IdFieldMapper;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.TypeFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Uid;
import org.apache.lucene.util.BytesRef;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;

public class SingleFieldsVisitor extends FieldsVisitor {

private String field;
/**
* {@linkplain StoredFieldVisitor} that loads a single field value.
*/
public final class SingleFieldsVisitor extends StoredFieldVisitor {
private final MappedFieldType field;
private final List<Object> destination;

public SingleFieldsVisitor(String field) {
super(false);
/**
* Build the field visitor;
* @param field the name of the field to load
* @param destination where to put the field's values
*/
public SingleFieldsVisitor(MappedFieldType field, List<Object> destination) {
this.field = field;
this.destination = destination;
}

@Override
public Status needsField(FieldInfo fieldInfo) throws IOException {
if (fieldInfo.name.equals(field)) {
public Status needsField(FieldInfo fieldInfo) {
if (fieldInfo.name.equals(field.name())) {
return Status.YES;
}
/*
* We can't return Status.STOP here because we could be loading
* multi-valued fields.
*/
return Status.NO;
}

public void reset(String field) {
this.field = field;
super.reset();
private void addValue(Object value) {
destination.add(field.valueForDisplay(value));
}

@Override
public void postProcess(MapperService mapperService) {
super.postProcess(mapperService);
if (id != null) {
addValue(IdFieldMapper.NAME, id);
}
if (type != null) {
addValue(TypeFieldMapper.NAME, type);
public void binaryField(FieldInfo fieldInfo, byte[] value) {
if (IdFieldMapper.NAME.equals(fieldInfo.name)) {
addValue(Uid.decodeId(value));
} else {
addValue(new BytesRef(value));
}
}

@Override
public void stringField(FieldInfo fieldInfo, byte[] bytes) {
addValue(new String(bytes, StandardCharsets.UTF_8));
}

@Override
public void intField(FieldInfo fieldInfo, int value) {
addValue(value);
}

@Override
public void longField(FieldInfo fieldInfo, long value) {
addValue(value);
}

@Override
public void floatField(FieldInfo fieldInfo, float value) {
addValue(value);
}

@Override
public void doubleField(FieldInfo fieldInfo, double value) {
addValue(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.index.fieldvisitor.SingleFieldsVisitor;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.TypeFieldMapper;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
Expand All @@ -48,13 +51,10 @@ public class LeafFieldsLookup implements Map {

private final Map<String, FieldLookup> cachedFieldData = new HashMap<>();

private final SingleFieldsVisitor fieldVisitor;

LeafFieldsLookup(MapperService mapperService, @Nullable String[] types, LeafReader reader) {
this.mapperService = mapperService;
this.types = types;
this.reader = reader;
this.fieldVisitor = new SingleFieldsVisitor(null);
}

public void setDocument(int docId) {
Expand Down Expand Up @@ -142,16 +142,23 @@ private FieldLookup loadFieldData(String name) {
cachedFieldData.put(name, data);
}
if (data.fields() == null) {
String fieldName = data.fieldType().name();
fieldVisitor.reset(fieldName);
try {
reader.document(docId, fieldVisitor);
fieldVisitor.postProcess(mapperService);
List<Object> storedFields = fieldVisitor.fields().get(data.fieldType().name());
data.fields(singletonMap(fieldName, storedFields));
} catch (IOException e) {
throw new ElasticsearchParseException("failed to load field [{}]", e, name);
List<Object> values;
if (TypeFieldMapper.NAME.equals(data.fieldType().name())) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach will not work in 6.x which has to be compatible with indices created in 5.x but I think it is quite sensible in master.

values = new ArrayList<>(1);
final DocumentMapper mapper = mapperService.documentMapper();
if (mapper != null) {
values.add(mapper.type());
}
} else {
values = new ArrayList<Object>(2);
SingleFieldsVisitor visitor = new SingleFieldsVisitor(data.fieldType(), values);
try {
reader.document(docId, visitor);
} catch (IOException e) {
throw new ElasticsearchParseException("failed to load field [{}]", e, name);
}
}
data.fields(singletonMap(data.fieldType().name(), values));
}
return data;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import org.elasticsearch.index.engine.EngineConfig;
import org.elasticsearch.index.engine.EngineTestCase;
import org.elasticsearch.index.engine.InternalEngine;
import org.elasticsearch.index.fieldvisitor.SingleFieldsVisitor;
import org.elasticsearch.index.mapper.IdFieldMapper;
import org.elasticsearch.index.mapper.ParseContext.Document;
import org.elasticsearch.index.mapper.ParsedDocument;
Expand Down Expand Up @@ -324,9 +323,9 @@ public void testLotsOfThreads() throws Exception {
try (Engine.GetResult getResult = engine.get(get, engine::acquireSearcher)) {
assertTrue("document not found", getResult.exists());
assertEquals(iteration, getResult.version());
SingleFieldsVisitor visitor = new SingleFieldsVisitor("test");
getResult.docIdAndVersion().reader.document(getResult.docIdAndVersion().docId, visitor);
assertEquals(Arrays.asList(testFieldValue), visitor.fields().get("test"));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect I could just call document(getResult.docIdAndVersion()) here and save some ceremony.

org.apache.lucene.document.Document document =
getResult.docIdAndVersion().reader.document(getResult.docIdAndVersion().docId);
assertEquals(new String[] {testFieldValue}, document.getValues("test"));
}
} catch (Exception t) {
throw new RuntimeException("failure on the [" + iteration + "] iteration of thread [" + threadId + "]", t);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import java.util.Collections;
import java.util.List;

import static org.mockito.AdditionalAnswers.returnsFirstArg;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
Expand All @@ -48,7 +47,9 @@ public void setUp() throws Exception {

MappedFieldType fieldType = mock(MappedFieldType.class);
when(fieldType.name()).thenReturn("field");
when(fieldType.valueForDisplay(anyObject())).then(returnsFirstArg());
// Add 10 when valueForDisplay is called so it is easy to be sure it *was* called
when(fieldType.valueForDisplay(anyObject())).then(invocation ->
(Double) invocation.getArguments()[0] + 10);

MapperService mapperService = mock(MapperService.class);
when(mapperService.fullName("field")).thenReturn(fieldType);
Expand Down Expand Up @@ -77,7 +78,7 @@ public void testBasicLookup() {
List<Object> values = fieldLookup.getValues();
assertNotNull(values);
assertEquals(1, values.size());
assertEquals(2.718, values.get(0));
assertEquals(12.718, values.get(0));
}

public void testLookupWithFieldAlias() {
Expand All @@ -87,6 +88,6 @@ public void testLookupWithFieldAlias() {
List<Object> values = fieldLookup.getValues();
assertNotNull(values);
assertEquals(1, values.size());
assertEquals(2.718, values.get(0));
assertEquals(12.718, values.get(0));
}
}