Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
164a85e
temorary solve
ajleong623 Jun 20, 2025
1825559
spotless
ajleong623 Jun 26, 2025
f16b39f
Merge branch 'opensearch-project:main' into wildcard-bug
ajleong623 Jul 17, 2025
1741b80
still have to change derived field generator
ajleong623 Jul 17, 2025
90f73e2
spotless apply
ajleong623 Jul 17, 2025
ffda262
added binary doc values fetcher
ajleong623 Jul 18, 2025
723ab8f
supported field types
ajleong623 Jul 18, 2025
b54c85e
spotlessapply
ajleong623 Jul 18, 2025
447c45d
small change
ajleong623 Jul 19, 2025
a8a9e84
disable skipping optimization by changing doc values to binary docs
ajleong623 Jul 19, 2025
3b5a2fe
skip sorting wildcard tests for before 3.2.0
ajleong623 Jul 28, 2025
2ef4902
Merge branch 'opensearch-project:main' into wildcard-bug
ajleong623 Jul 28, 2025
b7313cc
skip running wildcard searches with older versions
ajleong623 Jul 28, 2025
5e416a9
skip running wildcard searches with older versions
ajleong623 Jul 29, 2025
8b5181f
skip running wildcard searches with older versions
ajleong623 Jul 29, 2025
9084f00
original wildcard taml test
ajleong623 Jul 30, 2025
9de80c3
parse field for correct version
ajleong623 Jul 30, 2025
2a411a5
check correct version
ajleong623 Jul 31, 2025
69fad28
test skipping
ajleong623 Jul 31, 2025
2c876bf
update wildcard mapper
ajleong623 Jul 31, 2025
4b22303
update wildcard mapper
ajleong623 Jul 31, 2025
9ddc6e4
update wildcard mapper
ajleong623 Jul 31, 2025
19ae6c2
adjust version final
ajleong623 Jul 31, 2025
cf505a3
try to disable pruning
ajleong623 Aug 5, 2025
a9d940f
spotless and add license
ajleong623 Aug 5, 2025
9b8ed7f
java docs and test revert
ajleong623 Aug 6, 2025
9f40b3e
Merge branch 'opensearch-project:main' into wildcard-bug
ajleong623 Aug 6, 2025
56a94a7
update lucene serialization
ajleong623 Aug 6, 2025
d5761a1
Merge branch 'wildcard-bug' of https://github.com/ajleong623/OpenSear…
ajleong623 Aug 6, 2025
59ddd2e
delete binary doc values fetcher
ajleong623 Aug 6, 2025
7f1df80
fix casting
ajleong623 Aug 7, 2025
908593d
non pruning test coverage
ajleong623 Aug 7, 2025
dea8109
non pruning test coverage
ajleong623 Aug 8, 2025
d8cd0bf
Added more code coverage
ajleong623 Aug 8, 2025
1f5b18f
code coverage
ajleong623 Aug 8, 2025
a5f474d
Merge branch 'main' into wildcard-bug
ajleong623 Aug 9, 2025
101810e
retry
ajleong623 Aug 10, 2025
3135fa5
Merge branch 'wildcard-bug' of https://github.com/ajleong623/OpenSear…
ajleong623 Aug 10, 2025
751e6fb
retry
ajleong623 Aug 10, 2025
ff70c05
the test that failed last time is flaky as I have tried it out on the…
ajleong623 Aug 10, 2025
8023bef
cast parsing
ajleong623 Aug 10, 2025
ea82489
apply suggestions
ajleong623 Aug 13, 2025
fddd862
Merge branch 'main' into wildcard-bug
ajleong623 Aug 13, 2025
0d27c7a
reduce the number of methods in NonPruningSortField
ajleong623 Aug 13, 2025
c66b323
Merge branch 'wildcard-bug' of https://github.com/ajleong623/OpenSear…
ajleong623 Aug 13, 2025
e89f5bf
spotless
ajleong623 Aug 14, 2025
39aee3e
Merge branch 'opensearch-project:main' into wildcard-bug
ajleong623 Aug 14, 2025
9eeae28
Make sure wildcard search is only checked after 3.3.0
ajleong623 Aug 14, 2025
388d2f1
rerun for nondeterministic tests
ajleong623 Aug 15, 2025
f9be6f4
Merge branch 'wildcard-bug' of https://github.com/ajleong623/OpenSear…
ajleong623 Aug 15, 2025
73fb673
block casting error
ajleong623 Aug 15, 2025
d76264f
block casting error
ajleong623 Aug 15, 2025
1ef8c34
add check for casting type
ajleong623 Aug 15, 2025
ee2c0d9
smoke tests did not run
ajleong623 Aug 15, 2025
4330d51
rerun for smoke tests
ajleong623 Aug 16, 2025
57ea1ce
rerun for smoke tests
ajleong623 Aug 17, 2025
26fca74
Merge branch 'opensearch-project:main' into wildcard-bug
ajleong623 Aug 17, 2025
1412294
rerun for flaky detection
ajleong623 Aug 18, 2025
4b76d57
rerun for flaky detection
ajleong623 Aug 18, 2025
0535677
made changes based on suggestions
ajleong623 Aug 27, 2025
4b617fa
fix changelog order
ajleong623 Aug 27, 2025
eb61165
Merge branch 'main' into wildcard-bug
ajleong623 Aug 27, 2025
9a5d09a
fixed conditional
ajleong623 Aug 27, 2025
8fb2860
refactored testing for NonPruningSortedSetOrdinalsIndexFieldDataTests
ajleong623 Aug 28, 2025
b0205c5
timed out last time
ajleong623 Aug 28, 2025
a67685f
timed out last time
ajleong623 Aug 28, 2025
9779af4
Merge branch 'main' into wildcard-bug
ajleong623 Aug 28, 2025
e683b30
the negation actually did not go through
ajleong623 Aug 29, 2025
94ff235
Merge branch 'wildcard-bug' of https://github.com/ajleong623/OpenSear…
ajleong623 Aug 29, 2025
1f03ed0
fix casting error
ajleong623 Aug 29, 2025
7e11909
spotless
ajleong623 Aug 29, 2025
87f0c93
put serializer in the right place
ajleong623 Aug 30, 2025
931b896
Merge branch 'main' into wildcard-bug
ajleong623 Aug 30, 2025
aad91ce
rerun spotless
ajleong623 Aug 30, 2025
d75b6a9
retry spotless
ajleong623 Aug 30, 2025
73d13a2
retry spotless
ajleong623 Aug 31, 2025
329a9e6
retry spotless
ajleong623 Sep 1, 2025
f6112ac
updated serialization of NonPruningSortField
ajleong623 Sep 2, 2025
31f34af
Merge branch 'opensearch-project:main' into wildcard-bug
ajleong623 Sep 2, 2025
cdf3779
retry for flaky
ajleong623 Sep 2, 2025
505ae6e
retry for flaky
ajleong623 Sep 2, 2025
3dec070
updated serialization
ajleong623 Sep 3, 2025
5c80ab3
test coverage
ajleong623 Sep 3, 2025
04b2a72
retry for flaky
ajleong623 Sep 3, 2025
c1f59b6
retry for flaky
ajleong623 Sep 3, 2025
91ca440
retry for flaky
ajleong623 Sep 3, 2025
f033417
retry for flaky
ajleong623 Sep 4, 2025
e55207c
retry for flaky
ajleong623 Sep 5, 2025
07eeca3
retry for flaky
ajleong623 Sep 6, 2025
c205ff4
retry for flaky
ajleong623 Sep 7, 2025
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Replace centos:8 with almalinux:8 since centos docker images are deprecated ([#19154](https://github.com/opensearch-project/OpenSearch/pull/19154))
- Add CompletionStage variants to IndicesAdminClient as an alternative to ActionListener ([#19161](https://github.com/opensearch-project/OpenSearch/pull/19161))
- Remove cap on Java version used by forbidden APIs ([#19163](https://github.com/opensearch-project/OpenSearch/pull/19163))
- Disable pruning for `doc_values` for the wildcard field mapper ([#18568](https://github.com/opensearch-project/OpenSearch/pull/18568))

### Fixed
- Fix unnecessary refreshes on update preparation failures ([#15261](https://github.com/opensearch-project/OpenSearch/issues/15261))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -393,3 +393,23 @@ setup:
terms: { my_field: [ "\\*" ] }
- match: { hits.total.value: 1 }
- match: { hits.hits.0._id: "9" }

---
"sort on doc value enabled wildcard":
- skip:
version: " - 3.2.99"
reason: "sorting on doc value enabled wildcard has bug before 3.3.0"
- do:
search:
index: test
body:
query:
wildcard:
my_field:
value: "*"
sort:
- my_field.doc_values:
order: asc
size: 4
- match: { hits.total.value: 8 }
- match: { hits.hits.0._id: "8" }
19 changes: 19 additions & 0 deletions server/src/main/java/org/opensearch/common/lucene/Lucene.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
import org.opensearch.index.analysis.AnalyzerScope;
import org.opensearch.index.analysis.NamedAnalyzer;
import org.opensearch.index.fielddata.IndexFieldData;
import org.opensearch.index.fielddata.plain.NonPruningSortedSetOrdinalsIndexFieldData.NonPruningSortField;
import org.opensearch.search.sort.SortedWiderNumericSortField;

import java.io.IOException;
Expand Down Expand Up @@ -576,6 +577,24 @@ public static void writeSortField(StreamOutput out, SortField sortField) throws
);
newSortField.setMissingValue(sortField.getMissingValue());
sortField = newSortField;
} else if (sortField instanceof NonPruningSortField) {
// There are 2 cases of how NonPruningSortField wraps around its underlying sort field.
// Which are through the SortField class or SortedSetSortField class
// We will serialize the sort field based on the type of underlying sort field
// Here the underlying sort field is SortedSetSortField, therefore, we will follow the
// logic in serializing SortedSetSortField and also unwrap the SortField case.
NonPruningSortField nonPruningSortField = (NonPruningSortField) sortField;
if (nonPruningSortField.getDelegate().getClass() == SortedSetSortField.class) {
SortField newSortField = new SortField(
nonPruningSortField.getField(),
SortField.Type.STRING,
nonPruningSortField.getReverse()
);
newSortField.setMissingValue(nonPruningSortField.getMissingValue());
sortField = newSortField;
} else if (nonPruningSortField.getDelegate().getClass() == SortField.class) {
sortField = nonPruningSortField.getDelegate();
}
}

if (sortField.getClass() != SortField.class) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.index.fielddata.plain;

import org.apache.lucene.index.IndexSorter;
import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.search.FieldComparator;
import org.apache.lucene.search.FieldComparatorSource;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Pruning;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.SortedSetSelector;
import org.apache.lucene.search.SortedSetSortField;
import org.apache.lucene.store.DataInput;
import org.apache.lucene.util.BytesRef;
import org.opensearch.common.Nullable;
import org.opensearch.core.indices.breaker.CircuitBreakerService;
import org.opensearch.index.fielddata.IndexFieldData;
import org.opensearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested;
import org.opensearch.index.fielddata.IndexFieldDataCache;
import org.opensearch.index.fielddata.ScriptDocValues;
import org.opensearch.index.fielddata.fieldcomparator.BytesRefFieldComparatorSource;
import org.opensearch.index.mapper.WildcardFieldMapper;
import org.opensearch.search.MultiValueMode;
import org.opensearch.search.aggregations.support.ValuesSourceType;

import java.io.IOException;
import java.util.Comparator;
import java.util.function.Function;

/**
* Wrapper for {@link SortedSetOrdinalsIndexFieldData} which disables pruning optimization for
* sorting. Used in {@link WildcardFieldMapper}.
*
* @opensearch.internal
*/
public class NonPruningSortedSetOrdinalsIndexFieldData extends SortedSetOrdinalsIndexFieldData {

/**
* Builder for non-pruning sorted set ordinals
*
* @opensearch.internal
*/
public static class Builder implements IndexFieldData.Builder {
private final String name;
private final Function<SortedSetDocValues, ScriptDocValues<?>> scriptFunction;
private final ValuesSourceType valuesSourceType;

public Builder(String name, ValuesSourceType valuesSourceType) {
this(name, AbstractLeafOrdinalsFieldData.DEFAULT_SCRIPT_FUNCTION, valuesSourceType);
}

public Builder(String name, Function<SortedSetDocValues, ScriptDocValues<?>> scriptFunction, ValuesSourceType valuesSourceType) {
this.name = name;
this.scriptFunction = scriptFunction;
this.valuesSourceType = valuesSourceType;
}

@Override
public NonPruningSortedSetOrdinalsIndexFieldData build(IndexFieldDataCache cache, CircuitBreakerService breakerService) {
return new NonPruningSortedSetOrdinalsIndexFieldData(cache, name, valuesSourceType, breakerService, scriptFunction);
}
}

public NonPruningSortedSetOrdinalsIndexFieldData(
IndexFieldDataCache cache,
String fieldName,
ValuesSourceType valuesSourceType,
CircuitBreakerService breakerService,
Function<SortedSetDocValues, ScriptDocValues<?>> scriptFunction
) {
super(cache, fieldName, valuesSourceType, breakerService, scriptFunction);
}

@Override
public SortField sortField(@Nullable Object missingValue, MultiValueMode sortMode, Nested nested, boolean reverse) {
XFieldComparatorSource source = new BytesRefFieldComparatorSource(this, missingValue, sortMode, nested);
source.disableSkipping();
/*
Check if we can use a simple {@link SortedSetSortField} compatible with index sorting and
returns a custom sort field otherwise.
*/
if (nested != null
|| (sortMode != MultiValueMode.MAX && sortMode != MultiValueMode.MIN)
|| (source.sortMissingLast(missingValue) == false && source.sortMissingFirst(missingValue) == false)) {
return new NonPruningSortField(new SortField(getFieldName(), source, reverse));
}
SortField sortField = new NonPruningSortField(
new SortedSetSortField(
getFieldName(),
reverse,
sortMode == MultiValueMode.MAX ? SortedSetSelector.Type.MAX : SortedSetSelector.Type.MIN
)
);
sortField.setMissingValue(
source.sortMissingLast(missingValue) ^ reverse ? SortedSetSortField.STRING_LAST : SortedSetSortField.STRING_FIRST
);
return sortField;
}

/**
* {@link SortField} implementation which delegates calls to another {@link SortField}.
*
*/
public abstract class FilteredSortField extends SortField {
protected final SortField delegate;

protected FilteredSortField(SortField sortField) {
super(sortField.getField(), sortField.getType());
this.delegate = sortField;
}

@Override
public Object getMissingValue() {
return delegate.getMissingValue();
}

@Override
public void setMissingValue(Object missingValue) {
delegate.setMissingValue(missingValue);
}

@Override
public String getField() {
return delegate.getField();
}

@Override
public Type getType() {
return delegate.getType();
}

@Override
public boolean getReverse() {
return delegate.getReverse();
}

@Override
public FieldComparatorSource getComparatorSource() {
return delegate.getComparatorSource();
}

@Override
public String toString() {
return delegate.toString();
}

@Override
public boolean equals(Object o) {
return delegate.equals(o);
}

@Override
public int hashCode() {
return delegate.hashCode();
}

@Override
public void setBytesComparator(Comparator<BytesRef> b) {
delegate.setBytesComparator(b);
}

@Override
public Comparator<BytesRef> getBytesComparator() {
return delegate.getBytesComparator();
}

@Override
public FieldComparator<?> getComparator(int numHits, Pruning pruning) {
return delegate.getComparator(numHits, pruning);
}

@Override
public SortField rewrite(IndexSearcher searcher) throws IOException {
return delegate.rewrite(searcher);
}

@Override
public boolean needsScores() {
return delegate.needsScores();
}

@Override
public IndexSorter getIndexSorter() {
return delegate.getIndexSorter();
}

@Deprecated
@Override
public void setOptimizeSortWithIndexedData(boolean optimizeSortWithIndexedData) {
delegate.setOptimizeSortWithIndexedData(optimizeSortWithIndexedData);
}

@Deprecated
@Override
public boolean getOptimizeSortWithIndexedData() {
return delegate.getOptimizeSortWithIndexedData();
}

@Deprecated
@Override
public void setOptimizeSortWithPoints(boolean optimizeSortWithPoints) {
delegate.setOptimizeSortWithPoints(optimizeSortWithPoints);
}

@Deprecated
@Override
public boolean getOptimizeSortWithPoints() {
return delegate.getOptimizeSortWithPoints();
}
}

/**
* {@link SortField} extension which disables pruning in the comparator.
*
* @opensearch.internal
*/
public final class NonPruningSortField extends FilteredSortField {

private NonPruningSortField(SortField sortField) {
super(sortField);
}

public static Type readType(DataInput in) throws IOException {
return SortField.readType(in);
}

@Override
public FieldComparator<?> getComparator(int numHits, Pruning pruning) {
// explictly disable pruning
return delegate.getComparator(numHits, Pruning.NONE);
}

public SortField getDelegate() {
return delegate;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
import org.opensearch.index.analysis.IndexAnalyzers;
import org.opensearch.index.analysis.NamedAnalyzer;
import org.opensearch.index.fielddata.IndexFieldData;
import org.opensearch.index.fielddata.plain.SortedSetOrdinalsIndexFieldData;
import org.opensearch.index.fielddata.plain.NonPruningSortedSetOrdinalsIndexFieldData;
import org.opensearch.index.query.QueryShardContext;
import org.opensearch.search.DocValueFormat;
import org.opensearch.search.aggregations.support.CoreValuesSourceType;
Expand Down Expand Up @@ -366,7 +366,7 @@ NamedAnalyzer normalizer() {
@Override
public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName, Supplier<SearchLookup> searchLookup) {
failIfNoDocValues();
return new SortedSetOrdinalsIndexFieldData.Builder(name(), CoreValuesSourceType.BYTES);
return new NonPruningSortedSetOrdinalsIndexFieldData.Builder(name(), CoreValuesSourceType.BYTES);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,13 @@
import org.opensearch.common.util.io.IOUtils;
import org.opensearch.core.common.io.stream.NamedWriteableRegistry;
import org.opensearch.index.fielddata.IndexFieldData;
import org.opensearch.index.fielddata.IndexFieldData.XFieldComparatorSource;
import org.opensearch.index.fielddata.fieldcomparator.BytesRefFieldComparatorSource;
import org.opensearch.index.fielddata.fieldcomparator.DoubleValuesComparatorSource;
import org.opensearch.index.fielddata.fieldcomparator.FloatValuesComparatorSource;
import org.opensearch.index.fielddata.fieldcomparator.IntValuesComparatorSource;
import org.opensearch.index.fielddata.fieldcomparator.LongValuesComparatorSource;
import org.opensearch.index.fielddata.plain.NonPruningSortedSetOrdinalsIndexFieldData;
import org.opensearch.search.MultiValueMode;
import org.opensearch.test.OpenSearchTestCase;
import org.opensearch.test.VersionUtils;
Expand Down Expand Up @@ -582,6 +584,44 @@ public void testSortFieldSerialization() throws IOException {
assertEquals(sortFieldTuple.v2(), deserialized);
}

public void testNonpruningSortFieldSerialization() throws IOException {
NonPruningSortedSetOrdinalsIndexFieldData fieldData = new NonPruningSortedSetOrdinalsIndexFieldData(
null,
"field",
null,
null,
null
);

SortField nonPruningSortedSetField = fieldData.sortField(null, MultiValueMode.MAX, null, true);
SortField expected = new SortField(
nonPruningSortedSetField.getField(),
SortField.Type.STRING,
nonPruningSortedSetField.getReverse()
);
expected.setMissingValue(SortField.STRING_FIRST);
SortField deserialized1 = copyInstance(
nonPruningSortedSetField,
EMPTY_REGISTRY,
Lucene::writeSortField,
Lucene::readSortField,
VersionUtils.randomVersion(random())
);
assertEquals(expected, deserialized1);

SortField nonPruningSortField = fieldData.sortField(SortField.STRING_FIRST, MultiValueMode.SUM, null, true);
XFieldComparatorSource source = new BytesRefFieldComparatorSource(null, SortField.STRING_FIRST, MultiValueMode.SUM, null);
expected = new SortField(nonPruningSortField.getField(), source.reducedType(), nonPruningSortField.getReverse());
SortField deserialized2 = copyInstance(
nonPruningSortField,
EMPTY_REGISTRY,
Lucene::writeSortField,
Lucene::readSortField,
VersionUtils.randomVersion(random())
);
assertEquals(expected, deserialized2);
}

public void testSortValueSerialization() throws IOException {
Object sortValue = randomSortValue();
Object deserialized = copyInstance(
Expand Down
Loading
Loading