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 @@ -48,6 +48,7 @@
import org.opensearch.core.xcontent.XContentParser;
import org.opensearch.core.xcontent.XContentParser.Token;
import org.opensearch.index.compositeindex.datacube.DimensionType;
import org.opensearch.index.engine.dataformat.FieldTypeCapabilities;
import org.opensearch.index.fielddata.FieldData;
import org.opensearch.index.fielddata.IndexFieldData;
import org.opensearch.index.fielddata.IndexNumericFieldData;
Expand Down Expand Up @@ -252,6 +253,11 @@ public String typeName() {
return CONTENT_TYPE;
}

@Override
protected FieldTypeCapabilities.Capability searchCapability() {
return FieldTypeCapabilities.Capability.POINT_RANGE;
}

@Override
public Query termQuery(Object value, QueryShardContext context) {
failIfNotIndexedAndNoDocValues();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -489,11 +489,6 @@ protected void parseCreateField(ParseContext context) {
throw new UnsupportedOperationException();
}

@Override
protected void parseCreateFieldForPluggableFormat(ParseContext context) {
throw new UnsupportedOperationException();
}

@Override
protected void mergeOptions(FieldMapper other, List<String> conflicts) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,15 +178,6 @@ protected void parseCreateField(ParseContext context) throws IOException {
);
}

@Override
protected void parseCreateFieldForPluggableFormat(ParseContext context) throws IOException {
final int tokenCount = parseTokenCount(context);
if (tokenCount == Integer.MIN_VALUE) {
return;
}
context.documentInput().addField(fieldType(), tokenCount);
}

private int parseTokenCount(ParseContext context) throws IOException {
final String value;
if (context.externalValueSet()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.opensearch.common.settings.Settings;
import org.opensearch.common.util.FeatureFlags;
import org.opensearch.core.xcontent.XContentBuilder;
import org.opensearch.plugins.Plugin;

Expand Down Expand Up @@ -166,16 +164,4 @@ public void testParseCreateFieldForPluggableFormat() throws Exception {
assertNotNull(fieldMapper);
assertEquals("rank_feature", fieldMapper.typeName());
}

@LockFeatureFlag(FeatureFlags.PLUGGABLE_DATAFORMAT_EXPERIMENTAL_FLAG)
public void testPluggableDataFormatRankFeatureThrows() throws IOException {
Settings pluggableSettings = Settings.builder().put(getIndexSettings()).put("index.pluggable.dataformat.enabled", true).build();
DocumentMapper mapper = createDocumentMapper(pluggableSettings, fieldMapping(this::minimalMapping));
CapturingDocumentInput docInput = new CapturingDocumentInput();
MapperParsingException e = expectThrows(
MapperParsingException.class,
() -> mapper.parse(source(b -> b.field("field", 10)), docInput)
);
assertThat(e.getCause(), instanceOf(UnsupportedOperationException.class));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -155,18 +155,4 @@ public void testRejectMultiValuedFields() throws MapperParsingException, IOExcep
e.getCause().getMessage()
);
}

public void testParseCreateFieldForPluggableFormat() throws Exception {
DocumentMapper mapper = createDocumentMapper(fieldMapping(this::minimalMapping));
RankFeaturesFieldMapper fieldMapper = (RankFeaturesFieldMapper) mapper.mappers().getMapper("field");
assertNotNull(fieldMapper);
assertEquals("rank_features", fieldMapper.typeName());
}

public void testPluggableDataFormatRankFeaturesThrows() throws IOException {
DocumentMapper mapper = createDocumentMapper(fieldMapping(this::minimalMapping));
RankFeaturesFieldMapper rfMapper = (RankFeaturesFieldMapper) mapper.mappers().getMapper("field");
expectThrows(AssertionError.class, () -> rfMapper.parseCreateFieldForPluggableFormat(null));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@
import org.apache.lucene.search.SynonymQuery;
import org.apache.lucene.search.TermQuery;
import org.opensearch.common.lucene.search.MultiPhrasePrefixQuery;
import org.opensearch.common.settings.Settings;
import org.opensearch.common.util.FeatureFlags;
import org.opensearch.core.common.Strings;
import org.opensearch.core.xcontent.MediaTypeRegistry;
import org.opensearch.core.xcontent.XContentBuilder;
Expand Down Expand Up @@ -771,116 +769,4 @@ private static PrefixFieldMapper getPrefixFieldMapper(DocumentMapper defaultMapp
assertThat(mapper, instanceOf(PrefixFieldMapper.class));
return (PrefixFieldMapper) mapper;
}

@LockFeatureFlag(FeatureFlags.PLUGGABLE_DATAFORMAT_EXPERIMENTAL_FLAG)
public void testPluggableDataFormatSearchAsYouTypeValue() throws Exception {
Settings pluggableSettings = Settings.builder().put(getIndexSettings()).put("index.pluggable.dataformat.enabled", true).build();
DocumentMapper mapper = createDocumentMapper(
pluggableSettings,
mapping(b -> b.startObject("field").field("type", "search_as_you_type").endObject())
);
CapturingDocumentInput docInput = new CapturingDocumentInput();
mapper.parse(source(b -> b.field("field", "hello world")), docInput);

boolean found = docInput.getCapturedFields()
.stream()
.anyMatch(e -> e.getKey().name().equals("field") && e.getValue().equals("hello world"));
assertTrue("Expected search_as_you_type value", found);
}

@LockFeatureFlag(FeatureFlags.PLUGGABLE_DATAFORMAT_EXPERIMENTAL_FLAG)
public void testPluggableDataFormatSearchAsYouTypeNullSkipped() throws Exception {
Settings pluggableSettings = Settings.builder().put(getIndexSettings()).put("index.pluggable.dataformat.enabled", true).build();
DocumentMapper mapper = createDocumentMapper(
pluggableSettings,
mapping(b -> b.startObject("field").field("type", "search_as_you_type").endObject())
);
CapturingDocumentInput docInput = new CapturingDocumentInput();
mapper.parse(source(b -> b.nullField("field")), docInput);

boolean found = docInput.getCapturedFields().stream().anyMatch(e -> e.getKey().name().equals("field"));
assertFalse("Expected no field entry for null value", found);
}

@LockFeatureFlag(FeatureFlags.PLUGGABLE_DATAFORMAT_EXPERIMENTAL_FLAG)
public void testPluggableDataFormatSearchAsYouTypeExternalValue() throws Exception {
Settings pluggableSettings = Settings.builder().put(getIndexSettings()).put("index.pluggable.dataformat.enabled", true).build();
DocumentMapper mapper = createDocumentMapper(pluggableSettings, mapping(b -> {
b.startObject("text_field");
b.field("type", "text");
b.startObject("fields");
b.startObject("sayt").field("type", "search_as_you_type").endObject();
b.endObject();
b.endObject();
}));
CapturingDocumentInput docInput = new CapturingDocumentInput();
mapper.parse(source(b -> b.field("text_field", "external_sayt")), docInput);

boolean found = docInput.getCapturedFields()
.stream()
.anyMatch(e -> e.getKey().name().equals("text_field.sayt") && e.getValue().equals("external_sayt"));
assertTrue("Expected search_as_you_type sub-field captured with external value", found);
}

@LockFeatureFlag(FeatureFlags.PLUGGABLE_DATAFORMAT_EXPERIMENTAL_FLAG)
public void testPluggableDataFormatPrefixFieldMapperThrows() throws Exception {
DocumentMapper mapper = createDocumentMapper(mapping(b -> b.startObject("field").field("type", "search_as_you_type").endObject()));
PrefixFieldMapper prefixMapper = getPrefixFieldMapper(mapper, "field._index_prefix");
expectThrows(UnsupportedOperationException.class, () -> prefixMapper.parseCreateFieldForPluggableFormat(null));
}

@LockFeatureFlag(FeatureFlags.PLUGGABLE_DATAFORMAT_EXPERIMENTAL_FLAG)
public void testPluggableDataFormatShingleFieldMapperThrows() throws Exception {
DocumentMapper mapper = createDocumentMapper(mapping(b -> b.startObject("field").field("type", "search_as_you_type").endObject()));
ShingleFieldMapper shingleMapper = getShingleFieldMapper(mapper, "field._2gram");
expectThrows(UnsupportedOperationException.class, () -> shingleMapper.parseCreateFieldForPluggableFormat(null));
}

@LockFeatureFlag(FeatureFlags.PLUGGABLE_DATAFORMAT_EXPERIMENTAL_FLAG)
public void testPluggablePathEquivalenceWithLucenePath() throws Exception {
Settings pluggableSettings = Settings.builder().put(getIndexSettings()).put("index.pluggable.dataformat.enabled", true).build();

// Scenario 1: search_as_you_type value
{
DocumentMapper luceneMapper = createDocumentMapper(
mapping(b -> b.startObject("field").field("type", "search_as_you_type").endObject())
);
ParsedDocument luceneDoc = luceneMapper.parse(source(b -> b.field("field", "hello world")));
IndexableField[] luceneFields = luceneDoc.rootDoc().getFields("field");

DocumentMapper pluggableMapper = createDocumentMapper(
pluggableSettings,
mapping(b -> b.startObject("field").field("type", "search_as_you_type").endObject())
);
CapturingDocumentInput docInput = new CapturingDocumentInput();
pluggableMapper.parse(source(b -> b.field("field", "hello world")), docInput);

assertTrue("Lucene path should produce field 'field'", luceneFields.length > 0);
assertEquals("hello world", luceneFields[0].stringValue());
boolean pluggableFound = docInput.getCapturedFields()
.stream()
.anyMatch(e -> e.getKey().name().equals("field") && e.getValue().equals("hello world"));
assertTrue("Pluggable path should capture field 'field' with value 'hello world'", pluggableFound);
}

// Scenario 2: null value — no field produced
{
DocumentMapper luceneMapper = createDocumentMapper(
mapping(b -> b.startObject("field").field("type", "search_as_you_type").endObject())
);
ParsedDocument luceneDoc = luceneMapper.parse(source(b -> b.nullField("field")));
IndexableField[] luceneFields = luceneDoc.rootDoc().getFields("field");

DocumentMapper pluggableMapper = createDocumentMapper(
pluggableSettings,
mapping(b -> b.startObject("field").field("type", "search_as_you_type").endObject())
);
CapturingDocumentInput docInput = new CapturingDocumentInput();
pluggableMapper.parse(source(b -> b.nullField("field")), docInput);

assertEquals("Lucene path should produce no field 'field'", 0, luceneFields.length);
boolean pluggableHasField = docInput.getCapturedFields().stream().anyMatch(e -> e.getKey().name().equals("field"));
assertFalse("Pluggable path should produce no field 'field'", pluggableHasField);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,11 @@
import org.apache.lucene.tests.analysis.CannedTokenStream;
import org.apache.lucene.tests.analysis.MockTokenizer;
import org.apache.lucene.tests.analysis.Token;
import org.opensearch.common.settings.Settings;
import org.opensearch.common.util.FeatureFlags;
import org.opensearch.core.xcontent.XContentBuilder;
import org.opensearch.index.IndexSettings;
import org.opensearch.index.analysis.AnalyzerScope;
import org.opensearch.index.analysis.IndexAnalyzers;
import org.opensearch.index.analysis.NamedAnalyzer;
import org.opensearch.index.engine.dataformat.stub.MockCommitterEnginePlugin;
import org.opensearch.index.engine.dataformat.stub.MockDataFormatPlugin;
import org.opensearch.plugins.Plugin;

import java.io.IOException;
Expand All @@ -70,7 +66,7 @@ public class TokenCountFieldMapperTests extends MapperTestCase {

@Override
protected Collection<Plugin> getPlugins() {
return List.of(new MapperExtrasModulePlugin(), new MockDataFormatPlugin(), new MockCommitterEnginePlugin());
return List.of(new MapperExtrasModulePlugin());
}

@Override
Expand Down Expand Up @@ -224,81 +220,4 @@ private SourceToParse createDocument(String fieldValue) throws Exception {
private ParseContext.Document parseDocument(DocumentMapper mapper, SourceToParse request) {
return mapper.parse(request).docs().stream().findFirst().orElseThrow(() -> new IllegalStateException("Test object not parsed"));
}

private DocumentMapper createIndexWithTokenCountFieldPluggableDataFormat() throws IOException {
Settings pluggableSettings = Settings.builder().put(getIndexSettings()).put("index.pluggable.dataformat.enabled", true).build();
return createDocumentMapper(pluggableSettings, mapping(b -> {
b.startObject("test");
{
b.field("type", "text");
b.startObject("fields");
{
b.startObject("tc");
{
b.field("type", "token_count");
b.field("analyzer", "standard");
}
b.endObject();
}
b.endObject();
}
b.endObject();
}));
}

@LockFeatureFlag(FeatureFlags.PLUGGABLE_DATAFORMAT_EXPERIMENTAL_FLAG)
public void testPluggableDataFormatTokenCountValue() throws Exception {
DocumentMapper mapper = createIndexWithTokenCountFieldPluggableDataFormat();
CapturingDocumentInput docInput = new CapturingDocumentInput();
mapper.parse(createDocument("three tokens string"), docInput);

boolean found = docInput.getCapturedFields().stream().anyMatch(e -> e.getKey().name().equals("test.tc") && e.getValue().equals(3));
assertTrue("Expected token count of 3 for field test.tc", found);
}

@LockFeatureFlag(FeatureFlags.PLUGGABLE_DATAFORMAT_EXPERIMENTAL_FLAG)
public void testPluggableDataFormatTokenCountNullSkipped() throws Exception {
DocumentMapper mapper = createIndexWithTokenCountFieldPluggableDataFormat();
CapturingDocumentInput docInput = new CapturingDocumentInput();
mapper.parse(createDocument(null), docInput);

boolean hasTokenCountField = docInput.getCapturedFields().stream().anyMatch(e -> e.getKey().name().equals("test.tc"));
assertFalse("Expected no token count field for null value", hasTokenCountField);
}

@LockFeatureFlag(FeatureFlags.PLUGGABLE_DATAFORMAT_EXPERIMENTAL_FLAG)
public void testPluggablePathEquivalenceWithLucenePath() throws Exception {
// Scenario 1: token count value
{
DocumentMapper luceneMapper = createIndexWithTokenCountField(false);
ParseContext.Document luceneDoc = parseDocument(luceneMapper, createDocument("three tokens string"));
IndexableField luceneField = luceneDoc.getField("test.tc");

DocumentMapper pluggableMapper = createIndexWithTokenCountFieldPluggableDataFormat();
CapturingDocumentInput docInput = new CapturingDocumentInput();
pluggableMapper.parse(createDocument("three tokens string"), docInput);

assertNotNull("Lucene path should produce field 'test.tc'", luceneField);
assertEquals(3, luceneField.numericValue());
boolean pluggableFound = docInput.getCapturedFields()
.stream()
.anyMatch(e -> e.getKey().name().equals("test.tc") && e.getValue().equals(3));
assertTrue("Pluggable path should capture field 'test.tc' with value 3", pluggableFound);
}

// Scenario 2: null value — no field produced
{
DocumentMapper luceneMapper = createIndexWithTokenCountField(false);
ParseContext.Document luceneDoc = parseDocument(luceneMapper, createDocument(null));
IndexableField luceneField = luceneDoc.getField("test.tc");

DocumentMapper pluggableMapper = createIndexWithTokenCountFieldPluggableDataFormat();
CapturingDocumentInput docInput = new CapturingDocumentInput();
pluggableMapper.parse(createDocument(null), docInput);

assertNull("Lucene path should produce no field 'test.tc'", luceneField);
boolean pluggableHasField = docInput.getCapturedFields().stream().anyMatch(e -> e.getKey().name().equals("test.tc"));
assertFalse("Pluggable path should produce no field 'test.tc'", pluggableHasField);
}
}
}
Loading
Loading