-
Notifications
You must be signed in to change notification settings - Fork 24.9k
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
Use _refresh instead of reading from Translog in the RT GET case #20102
Changes from 6 commits
2738e00
ef73c41
1f9df32
5d201da
3f50c42
0034979
85738e7
455950f
bd92b9c
2eb849f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -85,7 +85,6 @@ public GetStats stats() { | |
return new GetStats(existsMetric.count(), TimeUnit.NANOSECONDS.toMillis(existsMetric.sum()), missingMetric.count(), TimeUnit.NANOSECONDS.toMillis(missingMetric.sum()), currentMetric.count()); | ||
} | ||
|
||
|
||
public GetResult get(String type, String id, String[] gFields, boolean realtime, long version, VersionType versionType, FetchSourceContext fetchSourceContext, boolean ignoreErrorsOnGeneratedFields) { | ||
currentMetric.inc(); | ||
try { | ||
|
@@ -182,140 +181,12 @@ private GetResult innerGet(String type, String id, String[] gFields, boolean rea | |
|
||
try { | ||
// break between having loaded it from translog (so we only have _source), and having a document to load | ||
if (get.docIdAndVersion() != null) { | ||
return innerGetLoadFromStoredFields(type, id, gFields, fetchSourceContext, get, mapperService); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you fix the indentation? |
||
} else { | ||
Translog.Source source = get.source(); | ||
|
||
Map<String, GetField> fields = null; | ||
SearchLookup searchLookup = null; | ||
|
||
// we can only load scripts that can run against the source | ||
Set<String> neededFields = new HashSet<>(); | ||
// add meta fields | ||
neededFields.add(RoutingFieldMapper.NAME); | ||
DocumentMapper docMapper = mapperService.documentMapper(type); | ||
if (docMapper.parentFieldMapper().active()) { | ||
neededFields.add(ParentFieldMapper.NAME); | ||
} | ||
if (docMapper.timestampFieldMapper().enabled()) { | ||
neededFields.add(TimestampFieldMapper.NAME); | ||
} | ||
if (docMapper.TTLFieldMapper().enabled()) { | ||
neededFields.add(TTLFieldMapper.NAME); | ||
} | ||
// add requested fields | ||
if (gFields != null) { | ||
neededFields.addAll(Arrays.asList(gFields)); | ||
} | ||
for (String field : neededFields) { | ||
if (SourceFieldMapper.NAME.equals(field)) { | ||
// dealt with when normalizing fetchSourceContext. | ||
continue; | ||
} | ||
Object value = null; | ||
if (field.equals(RoutingFieldMapper.NAME)) { | ||
value = source.routing; | ||
} else if (field.equals(ParentFieldMapper.NAME) && docMapper.parentFieldMapper().active()) { | ||
value = source.parent; | ||
} else if (field.equals(TimestampFieldMapper.NAME) && docMapper.timestampFieldMapper().enabled()) { | ||
value = source.timestamp; | ||
} else if (field.equals(TTLFieldMapper.NAME) && docMapper.TTLFieldMapper().enabled()) { | ||
// Call value for search with timestamp + ttl here to display the live remaining ttl value and be consistent with the search result display | ||
if (source.ttl > 0) { | ||
value = docMapper.TTLFieldMapper().valueForSearch(source.timestamp + source.ttl); | ||
} | ||
} else { | ||
if (searchLookup == null) { | ||
searchLookup = new SearchLookup(mapperService, null, new String[]{type}); | ||
searchLookup.source().setSource(source.source); | ||
} | ||
|
||
FieldMapper fieldMapper = docMapper.mappers().smartNameFieldMapper(field); | ||
if (fieldMapper == null) { | ||
if (docMapper.objectMappers().get(field) != null) { | ||
// Only fail if we know it is a object field, missing paths / fields shouldn't fail. | ||
throw new IllegalArgumentException("field [" + field + "] isn't a leaf field"); | ||
} | ||
} else if (shouldGetFromSource(ignoreErrorsOnGeneratedFields, docMapper, fieldMapper)) { | ||
List<Object> values = searchLookup.source().extractRawValues(field); | ||
if (!values.isEmpty()) { | ||
value = values; | ||
} | ||
|
||
} | ||
} | ||
if (value != null) { | ||
if (fields == null) { | ||
fields = new HashMap<>(2); | ||
} | ||
if (value instanceof List) { | ||
fields.put(field, new GetField(field, (List) value)); | ||
} else { | ||
fields.put(field, new GetField(field, Collections.singletonList(value))); | ||
} | ||
} | ||
} | ||
|
||
// deal with source, but only if it's enabled (we always have it from the translog) | ||
BytesReference sourceToBeReturned = null; | ||
SourceFieldMapper sourceFieldMapper = docMapper.sourceMapper(); | ||
if (fetchSourceContext.fetchSource() && sourceFieldMapper.enabled()) { | ||
|
||
sourceToBeReturned = source.source; | ||
|
||
// Cater for source excludes/includes at the cost of performance | ||
// We must first apply the field mapper filtering to make sure we get correct results | ||
// in the case that the fetchSourceContext white lists something that's not included by the field mapper | ||
|
||
boolean sourceFieldFiltering = sourceFieldMapper.includes().length > 0 || sourceFieldMapper.excludes().length > 0; | ||
boolean sourceFetchFiltering = fetchSourceContext.includes().length > 0 || fetchSourceContext.excludes().length > 0; | ||
if (sourceFieldFiltering || sourceFetchFiltering) { | ||
// TODO: The source might parsed and available in the sourceLookup but that one uses unordered maps so different. Do we care? | ||
Tuple<XContentType, Map<String, Object>> typeMapTuple = XContentHelper.convertToMap(source.source, true); | ||
XContentType sourceContentType = typeMapTuple.v1(); | ||
Map<String, Object> sourceAsMap = typeMapTuple.v2(); | ||
if (sourceFieldFiltering) { | ||
sourceAsMap = XContentMapValues.filter(sourceAsMap, sourceFieldMapper.includes(), sourceFieldMapper.excludes()); | ||
} | ||
if (sourceFetchFiltering) { | ||
sourceAsMap = XContentMapValues.filter(sourceAsMap, fetchSourceContext.includes(), fetchSourceContext.excludes()); | ||
} | ||
try { | ||
sourceToBeReturned = XContentFactory.contentBuilder(sourceContentType).map(sourceAsMap).bytes(); | ||
} catch (IOException e) { | ||
throw new ElasticsearchException("Failed to get type [" + type + "] and id [" + id + "] with includes/excludes set", e); | ||
} | ||
} | ||
} | ||
|
||
return new GetResult(shardId.getIndexName(), type, id, get.version(), get.exists(), sourceToBeReturned, fields); | ||
} | ||
} finally { | ||
get.release(); | ||
} | ||
} | ||
|
||
protected boolean shouldGetFromSource(boolean ignoreErrorsOnGeneratedFields, DocumentMapper docMapper, FieldMapper fieldMapper) { | ||
if (!fieldMapper.isGenerated()) { | ||
//if the field is always there we check if either source mapper is enabled, in which case we get the field | ||
// from source, or, if the field is stored, in which case we have to get if from source here also (we are in the translog phase, doc not indexed yet, we annot access the stored fields) | ||
return docMapper.sourceMapper().enabled() || fieldMapper.fieldType().stored(); | ||
} else { | ||
if (!fieldMapper.fieldType().stored()) { | ||
//if it is not stored, user will not get the generated field back | ||
return false; | ||
} else { | ||
if (ignoreErrorsOnGeneratedFields) { | ||
return false; | ||
} else { | ||
throw new ElasticsearchException("Cannot access field " + fieldMapper.name() + " from transaction log. You can only get this field after refresh() has been called."); | ||
} | ||
} | ||
|
||
} | ||
} | ||
|
||
private GetResult innerGetLoadFromStoredFields(String type, String id, String[] gFields, FetchSourceContext fetchSourceContext, Engine.GetResult get, MapperService mapperService) { | ||
Map<String, GetField> fields = null; | ||
BytesReference source = null; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -82,16 +82,9 @@ static TermVectorsResponse getTermVectors(IndexShard indexShard, TermVectorsRequ | |
Engine.GetResult get = indexShard.get(new Engine.Get(request.realtime(), uidTerm).version(request.version()).versionType(request.versionType())); | ||
|
||
Fields termVectorsByField = null; | ||
boolean docFromTranslog = get.source() != null; | ||
AggregatedDfs dfs = null; | ||
TermVectorsFilter termVectorsFilter = null; | ||
|
||
/* fetched from translog is treated as an artificial document */ | ||
if (docFromTranslog) { | ||
request.doc(get.source().source, false); | ||
termVectorsResponse.setDocVersion(get.version()); | ||
} | ||
|
||
/* handle potential wildcards in fields */ | ||
if (request.selectedFields() != null) { | ||
handleFieldWildcards(indexShard, request); | ||
|
@@ -103,12 +96,12 @@ static TermVectorsResponse getTermVectors(IndexShard indexShard, TermVectorsRequ | |
Versions.DocIdAndVersion docIdAndVersion = get.docIdAndVersion(); | ||
/* from an artificial document */ | ||
if (request.doc() != null) { | ||
termVectorsByField = generateTermVectorsFromDoc(indexShard, request, !docFromTranslog); | ||
termVectorsByField = generateTermVectorsFromDoc(indexShard, request, true); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this seems to be the only call site of |
||
// if no document indexed in shard, take the queried document itself for stats | ||
if (topLevelFields == null) { | ||
topLevelFields = termVectorsByField; | ||
} | ||
termVectorsResponse.setArtificial(!docFromTranslog); | ||
termVectorsResponse.setArtificial(true); | ||
termVectorsResponse.setExists(true); | ||
} | ||
/* or from an existing document */ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so Translog.Location does not need to implement Accountable anymore?