Skip to content
Merged
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
5 changes: 5 additions & 0 deletions docs/changelog/133080.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 133080
summary: "Disallow creating `semantic_text` fields in indices created prior to 8.11.0"
area: Relevance
type: bug
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@

import static org.apache.lucene.codecs.lucene99.Lucene99HnswVectorsFormat.DEFAULT_BEAM_WIDTH;
import static org.apache.lucene.codecs.lucene99.Lucene99HnswVectorsFormat.DEFAULT_MAX_CONN;
import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.INDEXED_BY_DEFAULT_INDEX_VERSION;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
Expand Down Expand Up @@ -100,7 +101,7 @@ private void indexMapping(XContentBuilder b, IndexVersion indexVersion) throws I
if (elementType != ElementType.FLOAT) {
b.field("element_type", elementType.toString());
}
if (indexVersion.onOrAfter(DenseVectorFieldMapper.INDEXED_BY_DEFAULT_INDEX_VERSION) || indexed) {
if (indexVersion.onOrAfter(INDEXED_BY_DEFAULT_INDEX_VERSION) || indexed) {
// Serialize if it's new index version, or it was not the default for previous indices
b.field("index", indexed);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ public final void testMeta() throws IOException {
);
}

public final void testDeprecatedBoostWarning() throws IOException {
public void testDeprecatedBoostWarning() throws IOException {
try {
createMapperService(DEPRECATED_BOOST_INDEX_VERSION, fieldMapping(b -> {
minimalMapping(b, DEPRECATED_BOOST_INDEX_VERSION);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
import java.util.function.Function;
import java.util.function.Supplier;

import static org.elasticsearch.index.IndexVersions.NEW_SPARSE_VECTOR;
import static org.elasticsearch.index.IndexVersions.SEMANTIC_TEXT_DEFAULTS_TO_BBQ_BACKPORT_8_X;
import static org.elasticsearch.inference.TaskType.SPARSE_EMBEDDING;
import static org.elasticsearch.inference.TaskType.TEXT_EMBEDDING;
Expand All @@ -122,6 +123,7 @@
*/
public class SemanticTextFieldMapper extends FieldMapper implements InferenceFieldMapper {
private static final Logger logger = LogManager.getLogger(SemanticTextFieldMapper.class);
public static final String UNSUPPORTED_INDEX_MESSAGE = "[semantic_text] is available on indices created with 8.11 or higher.";
public static final NodeFeature SEMANTIC_TEXT_SEARCH_INFERENCE_ID = new NodeFeature("semantic_text.search_inference_id", true);
public static final NodeFeature SEMANTIC_TEXT_DEFAULT_ELSER_2 = new NodeFeature("semantic_text.default_elser_2", true);
public static final NodeFeature SEMANTIC_TEXT_IN_OBJECT_FIELD_FIX = new NodeFeature("semantic_text.in_object_field_fix");
Expand Down Expand Up @@ -156,6 +158,9 @@ public static final TypeParser parser(Supplier<ModelRegistry> modelRegistry) {

public static BiConsumer<String, MappingParserContext> validateParserContext(String type) {
return (n, c) -> {
if (c.getIndexSettings().getIndexVersionCreated().before(NEW_SPARSE_VECTOR)) {
throw new UnsupportedOperationException(UNSUPPORTED_INDEX_MESSAGE);
}
if (InferenceMetadataFieldsMapper.isEnabled(c.getIndexSettings().getSettings()) == false) {
notInMultiFields(type).accept(n, c);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,11 @@
import static org.elasticsearch.xpack.inference.mapper.SemanticTextFieldMapper.DEFAULT_ELSER_2_INFERENCE_ID;
import static org.elasticsearch.xpack.inference.mapper.SemanticTextFieldMapper.DEFAULT_RESCORE_OVERSAMPLE;
import static org.elasticsearch.xpack.inference.mapper.SemanticTextFieldMapper.INDEX_OPTIONS_FIELD;
import static org.elasticsearch.xpack.inference.mapper.SemanticTextFieldMapper.UNSUPPORTED_INDEX_MESSAGE;
import static org.elasticsearch.xpack.inference.mapper.SemanticTextFieldTests.generateRandomChunkingSettings;
import static org.elasticsearch.xpack.inference.mapper.SemanticTextFieldTests.generateRandomChunkingSettingsOtherThan;
import static org.elasticsearch.xpack.inference.mapper.SemanticTextFieldTests.randomSemanticText;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
Expand Down Expand Up @@ -400,6 +402,57 @@ public void testInvalidTaskTypes() {
}
}

@Override
protected IndexVersion boostNotAllowedIndexVersion() {
return IndexVersions.NEW_SPARSE_VECTOR;
}

public void testOldIndexSemanticTextDenseVectorRaisesError() throws IOException {
final String fieldName = "field";
final XContentBuilder fieldMapping = fieldMapping(b -> {
b.field("type", "semantic_text");
b.field(INFERENCE_ID_FIELD, "test_inference_id");
b.startObject("model_settings");
b.field("task_type", "text_embedding");
b.field("dimensions", 384);
b.field("similarity", "cosine");
b.field("element_type", "float");
b.endObject();
});
assertOldIndexUnsupported(fieldMapping);
}

public void testOldIndexSemanticTextMinimalMappingRaisesError() throws IOException {
final XContentBuilder fieldMapping = fieldMapping(this::minimalMapping);
assertOldIndexUnsupported(fieldMapping);
}

public void testOldIndexSemanticTextSparseVersionRaisesError() throws IOException {
final XContentBuilder fieldMapping = fieldMapping(b -> {
b.field("type", "semantic_text");
b.field("inference_id", "another_inference_id");
b.startObject("model_settings");
b.field("task_type", "sparse_embedding");
b.endObject();
});
assertOldIndexUnsupported(fieldMapping);
}

private void assertOldIndexUnsupported(XContentBuilder fieldMapping) {

MapperParsingException exception = assertThrows(
MapperParsingException.class,
() -> createMapperService(
fieldMapping,
true,
IndexVersions.V_8_0_0,
IndexVersionUtils.getPreviousVersion(IndexVersions.NEW_SPARSE_VECTOR)
)
);
assertTrue(exception.getMessage().contains(UNSUPPORTED_INDEX_MESSAGE));
assertTrue(exception.getRootCause() instanceof UnsupportedOperationException);
}

public void testMultiFieldsSupport() throws IOException {
if (useLegacyFormat) {
Exception e = expectThrows(MapperParsingException.class, () -> createMapperService(fieldMapping(b -> {
Expand Down Expand Up @@ -1364,6 +1417,34 @@ public void testSpecifiedDenseVectorIndexOptions() throws IOException {

}

/**
* Semantic text version error supersedes deprecated boost warning
* @throws IOException
*/
@Override
public void testDeprecatedBoostWarning() throws IOException {
try {
createMapperService(DEPRECATED_BOOST_INDEX_VERSION, fieldMapping(b -> {
minimalMapping(b, DEPRECATED_BOOST_INDEX_VERSION);
b.field("boost", 2.0);
}));
String[] warnings = Strings.concatStringArrays(
getParseMinimalWarnings(DEPRECATED_BOOST_INDEX_VERSION),
new String[] { "Parameter [boost] on field [field] is deprecated and has no effect" }
);
assertWarnings(warnings);
} catch (MapperParsingException e) {
assertThat(
e.getMessage(),
anyOf(
containsString(UNSUPPORTED_INDEX_MESSAGE),
containsString("Unknown parameter [boost]"),
containsString("[boost : 2.0]")
)
);
}
}

public static SemanticTextIndexOptions randomSemanticTextIndexOptions() {
TaskType taskType = randomFrom(TaskType.SPARSE_EMBEDDING, TaskType.TEXT_EMBEDDING);
return randomSemanticTextIndexOptions(taskType);
Expand Down