Skip to content
Open
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 @@ -262,7 +262,7 @@ protected FieldTypeCapabilities.Capability searchCapability() {
public Query termQuery(Object value, QueryShardContext context) {
failIfNotIndexedAndNoDocValues();
long scaledValue = Math.round(scale(value));
Query query = NumberFieldMapper.NumberType.LONG.termQuery(name(), scaledValue, hasDocValues(), isSearchable());
Query query = NumberFieldMapper.NumberType.LONG.termQuery(name(), scaledValue, hasDocValues(), isEffectiveSearchable(context));
if (boost() != 1f) {
query = new BoostQuery(query, boost());
}
Expand All @@ -281,7 +281,7 @@ public Query termsQuery(List<?> values, QueryShardContext context) {
name(),
Collections.unmodifiableList(scaledValues),
hasDocValues(),
isSearchable()
isEffectiveSearchable(context)
);
if (boost() != 1f) {
query = new BoostQuery(query, boost());
Expand All @@ -307,7 +307,7 @@ public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower
includeLower,
includeUpper,
hasDocValues(),
isSearchable(),
isEffectiveSearchable(context),
context
);
if (boost() != 1f) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,16 @@
import org.opensearch.index.fielddata.IndexNumericFieldData;
import org.opensearch.index.fielddata.LeafNumericFieldData;
import org.opensearch.index.fielddata.SortedNumericDoubleValues;
import org.opensearch.index.query.QueryShardContext;
import org.opensearch.search.approximate.ApproximateScoreQuery;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class ScaledFloatFieldTypeTests extends FieldTypeTestCase {

public void testTermQuery() {
Expand All @@ -68,7 +72,7 @@ public void testTermQuery() {
long scaledValue = Math.round(value * ft.getScalingFactor());
Query dvQuery = SortedNumericDocValuesField.newSlowExactQuery("scaled_float", scaledValue);
Query query = new IndexOrDocValuesQuery(LongPoint.newExactQuery("scaled_float", scaledValue), dvQuery);
assertEquals(query, ft.termQuery(value, null));
assertEquals(query, ft.termQuery(value, MOCK_QSC));
}

public void testTermsQuery() {
Expand All @@ -80,7 +84,10 @@ public void testTermsQuery() {
long scaledValue1 = Math.round(value1 * ft.getScalingFactor());
double value2 = (randomDouble() * 2 - 1) * 10000;
long scaledValue2 = Math.round(value2 * ft.getScalingFactor());
assertEquals(LongField.newSetQuery("scaled_float", scaledValue1, scaledValue2), ft.termsQuery(Arrays.asList(value1, value2), null));
assertEquals(
LongField.newSetQuery("scaled_float", scaledValue1, scaledValue2),
ft.termsQuery(Arrays.asList(value1, value2), MOCK_QSC)
);
}

public void testRangeQuery() throws IOException {
Expand Down Expand Up @@ -343,4 +350,41 @@ public void testLargeNumberIndexingAndQuerying() throws IOException {
assertEquals("Terms query should find both documents", 2, searcher.count(termsQuery));
IOUtils.close(reader, dir);
}

/**
* On a pluggable-dataformat index the scaled_float mapper delegates to
* {@code NumberType.LONG} with {@code isEffectiveSearchable(context)} so the point-side of
* {@link IndexOrDocValuesQuery} is dropped. The Lucene secondary writes no BKD on such
* indices; keeping the point side would let the cost-based dispatch inside
* {@link IndexOrDocValuesQuery} pick an empty {@code PointValues} and return zero hits.
*/
public void testTermQueryUsesDocValuesWhenPluggableDataFormatEnabled() {
ScaledFloatFieldMapper.ScaledFloatFieldType ft = new ScaledFloatFieldMapper.ScaledFloatFieldType("scaled_float", 100.0);
Query query = ft.termQuery(13.5, mockPluggableDataFormatContext());
Query expected = SortedNumericDocValuesField.newSlowRangeQuery("scaled_float", 1350L, 1350L);
assertEquals(expected, query);
}

/** Terms queries route to the DV-only branch on pluggable-dataformat indices. */
public void testTermsQueryUsesDocValuesWhenPluggableDataFormatEnabled() {
ScaledFloatFieldMapper.ScaledFloatFieldType ft = new ScaledFloatFieldMapper.ScaledFloatFieldType("scaled_float", 100.0);
Query query = ft.termsQuery(Arrays.asList(1.0, 2.0), mockPluggableDataFormatContext());
Query expected = SortedNumericDocValuesField.newSlowSetQuery("scaled_float", 100L, 200L);
assertEquals(expected, query);
}

/** Range queries route to the DV-only branch on pluggable-dataformat indices. */
public void testRangeQueryUsesDocValuesWhenPluggableDataFormatEnabled() {
ScaledFloatFieldMapper.ScaledFloatFieldType ft = new ScaledFloatFieldMapper.ScaledFloatFieldType("scaled_float", 100.0);
Query query = ft.rangeQuery(1.0, 10.0, true, true, mockPluggableDataFormatContext());
Query expected = SortedNumericDocValuesField.newSlowRangeQuery("scaled_float", 100L, 1000L);
assertEquals(expected, query);
}

/** A {@link QueryShardContext} mock that reports the pluggable-dataformat gate as enabled. */
private static QueryShardContext mockPluggableDataFormatContext() {
QueryShardContext ctx = mock(QueryShardContext.class);
when(ctx.isPluggableDataFormatEnabled()).thenReturn(true);
return ctx;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,10 @@ public DocValueFormat docValueFormat(@Nullable String format, ZoneId timeZone) {
@Override
public Query termQuery(Object value, QueryShardContext context) {
failIfNotIndexedAndNoDocValues();
if (!isSearchable()) {
if (!isEffectiveSearchable(context)) {
return SortedNumericDocValuesField.newSlowExactQuery(name(), Values.TRUE.bytesEquals(indexedValueForSearch(value)) ? 1 : 0);
}

Query query = new TermQuery(new Term(name(), indexedValueForSearch(value)));
if (boost() != 1f) {
query = new BoostQuery(query, boost());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -538,8 +538,7 @@ public Query rangeQuery(
(l, u, nowUsed) -> {
Query dvQuery = hasDocValues() ? SortedNumericDocValuesField.newSlowRangeQuery(name(), l, u) : null;

// Not searchable. Must have doc values.
if (!isSearchable()) {
if (!isEffectiveSearchable(context)) {
if (context.indexSortedOnField(name())) {
dvQuery = new IndexSortSortedNumericDocValuesRangeQuery(name(), l, u, dvQuery);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,10 +302,11 @@ public Query termQuery(Object value, @Nullable QueryShardContext context) {
true
);
}
if (isSearchable() && hasDocValues()) {
boolean effectiveSearchable = isEffectiveSearchable(context);
if (effectiveSearchable && hasDocValues()) {
return new IndexOrDocValuesQuery(pointQuery, dvQuery);
} else {
return isSearchable() ? pointQuery : dvQuery;
return effectiveSearchable ? pointQuery : dvQuery;
}
}

Expand All @@ -317,7 +318,7 @@ public Query termsQuery(List<?> values, QueryShardContext context) {
List<PointRangeQuery> masks = new ArrayList<>();
parseIps(values, concreteIPs, masks);

if (!isSearchable()) {
if (!isEffectiveSearchable(context)) {
return hasDocValues() ? docValuesTermsQuery(concreteIPs, masks) : new MatchNoDocsQuery("never happened");
}

Expand Down Expand Up @@ -440,10 +441,11 @@ public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower
true
);
}
if (isSearchable() && hasDocValues()) {
boolean effectiveSearchable = isEffectiveSearchable(context);
if (effectiveSearchable && hasDocValues()) {
return new IndexOrDocValuesQuery(pointQuery, dvQuery);
} else {
return isSearchable() ? pointQuery : dvQuery;
return effectiveSearchable ? pointQuery : dvQuery;
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,22 @@ public boolean isSearchable() {
return isIndexed;
}

/**
* Returns whether this numeric field should be advertised as searchable to the
* per-type query factory. On indices backed by a pluggable dataformat (composite
* primary + Lucene secondary), the Lucene secondary writes no BKD for numeric
* fields, so the point-side of {@link org.apache.lucene.search.IndexOrDocValuesQuery}
* reports {@code cost=0} and wins the cost race — returning zero hits. Routing
* through the pure doc-values branch (by treating the field as not-searchable)
* avoids that trap and executes correctly against the codec-served DV column.
*
* <p>Non-pluggable-dataformat indices retain their normal {@link #isSearchable()}
* behavior so the BKD fast path is preserved.
*/
public boolean isEffectiveSearchable(QueryShardContext context) {
return isSearchable() && !context.isPluggableDataFormatEnabled();
}

/**
* Returns true if the field is stored separately.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1989,7 +1989,7 @@ public NumericType numericType() {
@Override
public Query termQuery(Object value, QueryShardContext context) {
failIfNotIndexedAndNoDocValues();
Query query = type.termQuery(name(), value, hasDocValues(), isSearchable());
Query query = type.termQuery(name(), value, hasDocValues(), isEffectiveSearchable(context));
if (boost() != 1f) {
query = new BoostQuery(query, boost());
}
Expand All @@ -1999,16 +1999,16 @@ public Query termQuery(Object value, QueryShardContext context) {
@Override
public Query termsQuery(List values, QueryShardContext context) {
failIfNotIndexedAndNoDocValues();
Query query = type.termsQuery(name(), values, hasDocValues(), isSearchable());
Query query = type.termsQuery(name(), values, hasDocValues(), isEffectiveSearchable(context));
if (boost() != 1f) {
query = new BoostQuery(query, boost());
}
return query;
}

public Query bitmapQuery(BytesArray bitmap) {
public Query bitmapQuery(BytesArray bitmap, QueryShardContext context) {
failIfNotIndexedAndNoDocValues();
return type.bitmapQuery(name(), bitmap, isSearchable(), hasDocValues());
return type.bitmapQuery(name(), bitmap, isEffectiveSearchable(context), hasDocValues());
}

@Override
Expand All @@ -2021,7 +2021,7 @@ public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower
includeLower,
includeUpper,
hasDocValues(),
isSearchable(),
isEffectiveSearchable(context),
context
);
if (boost() != 1f) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,17 @@ public IndexSettings getIndexSettings() {
return indexSettings;
}

/**
* Null-safe check for the pluggable-dataformat gate. Returns {@code true} only when this
* context has index-scoped settings and the setting is enabled. Callers use this to route
* query construction (e.g. numeric range/term/bitmap) through the pure doc-values branch
* on pluggable-dataformat indices, where the Lucene secondary writes no BKD for numeric
* fields.
*/
public boolean isPluggableDataFormatEnabled() {
return indexSettings != null && indexSettings.isPluggableDataFormatEnabled();
}

/**
* Return the MapperService.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ protected Query doToQuery(QueryShardContext context) throws IOException {
&& values.size() == 1
&& values.get(0) instanceof BytesArray bytesArray
&& fieldType.unwrap() instanceof NumberFieldMapper.NumberFieldType numberFieldType) {
return numberFieldType.bitmapQuery(bytesArray);
return numberFieldType.bitmapQuery(bytesArray, context);
}
return fieldType.termsQuery(values, context);
}
Expand Down
Loading