Core: Terms filter lookup caching should cache values, not filters.
The terms filter lookup mechanism today caches filters. Because of this, the cache values depend on two things: the values that can be found in the lookup index AND the mapping of the local index, since changing the mapping can change the way that the filter is parsed. We should make the cache depend solely on the content of the lookup index. For instance the issue I was seeing was due to the following scenario: - create index1 with _id indexed - run terms filter with lookup, the parsed filter looks like `_id: 1 OR _id: 2` - remove index1 - create index1 with _id not indexed - run terms filter without lookup, the parsed filter is `_uid: type#1 OR _uid: type#2` (the _id field mapper knows how to use the _uid field when _id is not indexed) - run terms filter with lookup, the filter is fetched from the cache: `_id: 1 OR _id: 2` but does not match anything since `_id` is not indexed. Close #9027
This commit is contained in:
parent
24591b3c70
commit
67eba23b2d
|
@ -188,18 +188,8 @@ public class TermsFilterParser implements FilterParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
// external lookup, use it
|
// external lookup, use it
|
||||||
TermsLookup termsLookup = new TermsLookup(fieldMapper, lookupIndex, lookupType, lookupId, lookupRouting, lookupPath, parseContext);
|
TermsLookup termsLookup = new TermsLookup(lookupIndex, lookupType, lookupId, lookupRouting, lookupPath, parseContext);
|
||||||
|
terms.addAll(termsFilterCache.terms(termsLookup, lookupCache, cacheKey));
|
||||||
Filter filter = termsFilterCache.termsFilter(termsLookup, lookupCache, cacheKey);
|
|
||||||
if (filter == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// cache the whole filter by default, or if explicitly told to
|
|
||||||
if (cache != null) {
|
|
||||||
filter = parseContext.cacheFilter(filter, cacheKey, cache);
|
|
||||||
}
|
|
||||||
return filter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (terms.isEmpty()) {
|
if (terms.isEmpty()) {
|
||||||
|
|
|
@ -22,9 +22,10 @@ package org.elasticsearch.indices.cache.filter.terms;
|
||||||
import com.google.common.cache.Cache;
|
import com.google.common.cache.Cache;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.common.cache.Weigher;
|
import com.google.common.cache.Weigher;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
import org.apache.lucene.search.Filter;
|
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.apache.lucene.util.RamUsageEstimator;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.action.get.GetRequest;
|
import org.elasticsearch.action.get.GetRequest;
|
||||||
import org.elasticsearch.action.get.GetResponse;
|
import org.elasticsearch.action.get.GetResponse;
|
||||||
|
@ -33,7 +34,6 @@ import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.component.AbstractComponent;
|
import org.elasticsearch.common.component.AbstractComponent;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.lucene.HashedBytesRef;
|
import org.elasticsearch.common.lucene.HashedBytesRef;
|
||||||
import org.elasticsearch.common.lucene.search.Queries;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.unit.ByteSizeUnit;
|
import org.elasticsearch.common.unit.ByteSizeUnit;
|
||||||
import org.elasticsearch.common.unit.ByteSizeValue;
|
import org.elasticsearch.common.unit.ByteSizeValue;
|
||||||
|
@ -49,7 +49,9 @@ import java.util.concurrent.TimeUnit;
|
||||||
*/
|
*/
|
||||||
public class IndicesTermsFilterCache extends AbstractComponent {
|
public class IndicesTermsFilterCache extends AbstractComponent {
|
||||||
|
|
||||||
private static TermsFilterValue NO_TERMS = new TermsFilterValue(0, Queries.MATCH_NO_FILTER);
|
private static final long BASE_RAM_BYTES_STRING = RamUsageEstimator.shallowSizeOfInstance(String.class) + RamUsageEstimator.NUM_BYTES_OBJECT_HEADER;
|
||||||
|
private static final long BASE_RAM_BYTES_BYTES_REF = RamUsageEstimator.shallowSizeOfInstance(BytesRef.class) + RamUsageEstimator.NUM_BYTES_OBJECT_HEADER;
|
||||||
|
private static final TermsFilterValue NO_TERMS = new TermsFilterValue(0, ImmutableList.of());
|
||||||
|
|
||||||
private final Client client;
|
private final Client client;
|
||||||
|
|
||||||
|
@ -78,10 +80,9 @@ public class IndicesTermsFilterCache extends AbstractComponent {
|
||||||
this.cache = builder.build();
|
this.cache = builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
public List<Object> terms(final TermsLookup lookup, boolean cacheLookup, @Nullable HashedBytesRef cacheKey) throws RuntimeException {
|
||||||
public Filter termsFilter(final TermsLookup lookup, boolean cacheLookup, @Nullable HashedBytesRef cacheKey) throws RuntimeException {
|
|
||||||
if (!cacheLookup) {
|
if (!cacheLookup) {
|
||||||
return buildTermsFilterValue(lookup).filter;
|
return buildTermsFilterValue(lookup).values;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashedBytesRef key;
|
HashedBytesRef key;
|
||||||
|
@ -96,7 +97,7 @@ public class IndicesTermsFilterCache extends AbstractComponent {
|
||||||
public TermsFilterValue call() throws Exception {
|
public TermsFilterValue call() throws Exception {
|
||||||
return buildTermsFilterValue(lookup);
|
return buildTermsFilterValue(lookup);
|
||||||
}
|
}
|
||||||
}).filter;
|
}).values;
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
if (e.getCause() instanceof RuntimeException) {
|
if (e.getCause() instanceof RuntimeException) {
|
||||||
throw (RuntimeException) e.getCause();
|
throw (RuntimeException) e.getCause();
|
||||||
|
@ -114,17 +115,16 @@ public class IndicesTermsFilterCache extends AbstractComponent {
|
||||||
if (values.isEmpty()) {
|
if (values.isEmpty()) {
|
||||||
return NO_TERMS;
|
return NO_TERMS;
|
||||||
}
|
}
|
||||||
Filter filter = lookup.getFieldMapper().termsFilter(values, lookup.getQueryParseContext());
|
return new TermsFilterValue(estimateSizeInBytes(values), ImmutableList.copyOf(values));
|
||||||
return new TermsFilterValue(estimateSizeInBytes(values), filter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long estimateSizeInBytes(List<Object> terms) {
|
long estimateSizeInBytes(List<Object> terms) {
|
||||||
long size = 8;
|
long size = 8 + terms.size() * RamUsageEstimator.NUM_BYTES_OBJECT_REF;
|
||||||
for (Object term : terms) {
|
for (Object term : terms) {
|
||||||
if (term instanceof BytesRef) {
|
if (term instanceof BytesRef) {
|
||||||
size += ((BytesRef) term).length;
|
size += BASE_RAM_BYTES_BYTES_REF + ((BytesRef) term).length;
|
||||||
} else if (term instanceof String) {
|
} else if (term instanceof String) {
|
||||||
size += ((String) term).length() / 2;
|
size += BASE_RAM_BYTES_STRING + ((String) term).length() * RamUsageEstimator.NUM_BYTES_CHAR;
|
||||||
} else {
|
} else {
|
||||||
size += 4;
|
size += 4;
|
||||||
}
|
}
|
||||||
|
@ -150,14 +150,13 @@ public class IndicesTermsFilterCache extends AbstractComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: if TermsFilter exposed sizeInBytes, we won't need this wrapper
|
|
||||||
static class TermsFilterValue {
|
static class TermsFilterValue {
|
||||||
public final long sizeInBytes;
|
public final long sizeInBytes;
|
||||||
public final Filter filter;
|
public final ImmutableList<Object> values;
|
||||||
|
|
||||||
TermsFilterValue(long sizeInBytes, Filter filter) {
|
TermsFilterValue(long sizeInBytes, ImmutableList<Object> values) {
|
||||||
this.sizeInBytes = sizeInBytes;
|
this.sizeInBytes = sizeInBytes;
|
||||||
this.filter = filter;
|
this.values = values;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,15 +20,12 @@
|
||||||
package org.elasticsearch.indices.cache.filter.terms;
|
package org.elasticsearch.indices.cache.filter.terms;
|
||||||
|
|
||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.index.mapper.FieldMapper;
|
|
||||||
import org.elasticsearch.index.query.QueryParseContext;
|
import org.elasticsearch.index.query.QueryParseContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
public class TermsLookup {
|
public class TermsLookup {
|
||||||
|
|
||||||
private final FieldMapper fieldMapper;
|
|
||||||
|
|
||||||
private final String index;
|
private final String index;
|
||||||
private final String type;
|
private final String type;
|
||||||
private final String id;
|
private final String id;
|
||||||
|
@ -38,8 +35,7 @@ public class TermsLookup {
|
||||||
@Nullable
|
@Nullable
|
||||||
private final QueryParseContext queryParseContext;
|
private final QueryParseContext queryParseContext;
|
||||||
|
|
||||||
public TermsLookup(FieldMapper fieldMapper, String index, String type, String id, String routing, String path, @Nullable QueryParseContext queryParseContext) {
|
public TermsLookup(String index, String type, String id, String routing, String path, @Nullable QueryParseContext queryParseContext) {
|
||||||
this.fieldMapper = fieldMapper;
|
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
@ -48,10 +44,6 @@ public class TermsLookup {
|
||||||
this.queryParseContext = queryParseContext;
|
this.queryParseContext = queryParseContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldMapper getFieldMapper() {
|
|
||||||
return fieldMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getIndex() {
|
public String getIndex() {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
@ -78,6 +70,6 @@ public class TermsLookup {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return fieldMapper.names().fullName() + ":" + index + "/" + type + "/" + id + "/" + path;
|
return index + "/" + type + "/" + id + "/" + path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue