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/119967.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 119967
summary: Add `index_options` to `semantic_text` field mappings
area: Mapping
type: enhancement
issues: [ ]

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.index.mapper.vectors;

import org.elasticsearch.xcontent.ToXContent;

/**
* Represents general index options that can be attached to a semantic or vector field.
*/
public interface IndexOptions extends ToXContent {}
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ private static DenseVectorFieldMapper.RescoreVector randomRescoreVector() {
return new DenseVectorFieldMapper.RescoreVector(randomBoolean() ? 0 : randomFloatBetween(1.0F, 10.0F, false));
}

private DenseVectorFieldMapper.IndexOptions randomIndexOptionsNonQuantized() {
private DenseVectorFieldMapper.DenseVectorIndexOptions randomIndexOptionsNonQuantized() {
return randomFrom(
new DenseVectorFieldMapper.HnswIndexOptions(randomIntBetween(1, 100), randomIntBetween(1, 10_000)),
new DenseVectorFieldMapper.FlatIndexOptions()
);
}

private DenseVectorFieldMapper.IndexOptions randomIndexOptionsAll() {
public static DenseVectorFieldMapper.DenseVectorIndexOptions randomIndexOptionsAll() {
return randomFrom(
new DenseVectorFieldMapper.HnswIndexOptions(randomIntBetween(1, 100), randomIntBetween(1, 10_000)),
new DenseVectorFieldMapper.Int8HnswIndexOptions(
Expand Down Expand Up @@ -93,11 +93,13 @@ private DenseVectorFieldMapper.IndexOptions randomIndexOptionsAll() {
);
}

private DenseVectorFieldMapper.IndexOptions randomIndexOptionsHnswQuantized() {
private DenseVectorFieldMapper.DenseVectorIndexOptions randomIndexOptionsHnswQuantized() {
return randomIndexOptionsHnswQuantized(randomBoolean() ? null : randomRescoreVector());
}

private DenseVectorFieldMapper.IndexOptions randomIndexOptionsHnswQuantized(DenseVectorFieldMapper.RescoreVector rescoreVector) {
private DenseVectorFieldMapper.DenseVectorIndexOptions randomIndexOptionsHnswQuantized(
DenseVectorFieldMapper.RescoreVector rescoreVector
) {
return randomFrom(
new DenseVectorFieldMapper.Int8HnswIndexOptions(
randomIntBetween(1, 100),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.util.Set;

import static org.elasticsearch.xpack.inference.mapper.SemanticTextFieldMapper.SEMANTIC_TEXT_EXCLUDE_SUB_FIELDS_FROM_FIELD_CAPS;
import static org.elasticsearch.xpack.inference.mapper.SemanticTextFieldMapper.SEMANTIC_TEXT_INDEX_OPTIONS;
import static org.elasticsearch.xpack.inference.mapper.SemanticTextFieldMapper.SEMANTIC_TEXT_SUPPORT_CHUNKING_CONFIG;
import static org.elasticsearch.xpack.inference.queries.SemanticKnnVectorQueryRewriteInterceptor.SEMANTIC_KNN_FILTER_FIX;
import static org.elasticsearch.xpack.inference.queries.SemanticKnnVectorQueryRewriteInterceptor.SEMANTIC_KNN_VECTOR_QUERY_REWRITE_INTERCEPTION_SUPPORTED;
Expand Down Expand Up @@ -70,7 +71,8 @@ public Set<NodeFeature> getTestFeatures() {
SemanticTextFieldMapper.SEMANTIC_TEXT_HANDLE_EMPTY_INPUT,
SEMANTIC_TEXT_SUPPORT_CHUNKING_CONFIG,
SEMANTIC_TEXT_MATCH_ALL_HIGHLIGHTER,
SEMANTIC_TEXT_EXCLUDE_SUB_FIELDS_FROM_FIELD_CAPS
SEMANTIC_TEXT_EXCLUDE_SUB_FIELDS_FROM_FIELD_CAPS,
SEMANTIC_TEXT_INDEX_OPTIONS
);
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.inference.mapper;

import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.IndexVersion;
import org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper;
import org.elasticsearch.index.mapper.vectors.IndexOptions;
import org.elasticsearch.xcontent.ToXContent;
import org.elasticsearch.xcontent.XContentBuilder;

import java.io.IOException;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;

/**
* Represents index options for a semantic_text field.
* We represent semantic_text index_options as nested within their respective type. For example:
* "index_options": {
* "dense_vector": {
* "type": "bbq_hnsw
* }
* }
*/
public class SemanticTextIndexOptions implements ToXContent {

private static final String TYPE_FIELD = "type";

private final SupportedIndexOptions type;
private final IndexOptions indexOptions;

public SemanticTextIndexOptions(SupportedIndexOptions type, IndexOptions indexOptions) {
this.type = type;
this.indexOptions = indexOptions;
}

public SupportedIndexOptions type() {
return type;
}

public IndexOptions indexOptions() {
return indexOptions;
}

public enum SupportedIndexOptions {
DENSE_VECTOR("dense_vector") {
@Override
public IndexOptions parseIndexOptions(String fieldName, Map<String, Object> map, IndexVersion indexVersion) {
return parseDenseVectorIndexOptionsFromMap(fieldName, map, indexVersion);
}
};

public final String value;

SupportedIndexOptions(String value) {
this.value = value;
}

public abstract IndexOptions parseIndexOptions(String fieldName, Map<String, Object> map, IndexVersion indexVersion);

public static SupportedIndexOptions fromValue(String value) {
return Arrays.stream(SupportedIndexOptions.values())
.filter(option -> option.value.equals(value))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Unknown index options type [" + value + "]"));
}
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(type.value.toLowerCase(Locale.ROOT));
indexOptions.toXContent(builder, params);
builder.endObject();
return builder;
}

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

private static DenseVectorFieldMapper.DenseVectorIndexOptions parseDenseVectorIndexOptionsFromMap(
String fieldName,
Map<String, Object> map,
IndexVersion indexVersion
) {
try {
Object type = map.remove(TYPE_FIELD);
if (type == null) {
throw new IllegalArgumentException("Required " + TYPE_FIELD);
}
DenseVectorFieldMapper.VectorIndexType vectorIndexType = DenseVectorFieldMapper.VectorIndexType.fromString(
XContentMapValues.nodeStringValue(type, null)
).orElseThrow(() -> new IllegalArgumentException("Unsupported index options " + TYPE_FIELD + " " + type));

return vectorIndexType.parseIndexOptions(fieldName, map, indexVersion);
} catch (Exception exc) {
throw new ElasticsearchException(exc);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,5 +114,4 @@ static IndexVersion getRandomCompatibleIndexVersion(boolean useLegacyFormat) {
);
}
}

}
Loading