Skip to content

Commit d306eae

Browse files
committed
Add chunking to test inference service
1 parent 7aaaee8 commit d306eae

File tree

6 files changed

+77
-12
lines changed

6 files changed

+77
-12
lines changed

x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/AbstractTestInferenceService.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import org.elasticsearch.common.io.stream.StreamInput;
1414
import org.elasticsearch.common.io.stream.StreamOutput;
1515
import org.elasticsearch.core.TimeValue;
16+
import org.elasticsearch.inference.ChunkingSettings;
17+
import org.elasticsearch.inference.ChunkingStrategy;
1618
import org.elasticsearch.inference.InferenceService;
1719
import org.elasticsearch.inference.Model;
1820
import org.elasticsearch.inference.ModelConfigurations;
@@ -22,9 +24,13 @@
2224
import org.elasticsearch.inference.TaskSettings;
2325
import org.elasticsearch.inference.TaskType;
2426
import org.elasticsearch.xcontent.XContentBuilder;
27+
import org.elasticsearch.xpack.inference.chunking.WordBoundaryChunker;
28+
import org.elasticsearch.xpack.inference.chunking.WordBoundaryChunkingSettings;
2529

2630
import java.io.IOException;
31+
import java.util.ArrayList;
2732
import java.util.HashMap;
33+
import java.util.List;
2834
import java.util.Map;
2935
import java.util.Random;
3036

@@ -105,6 +111,33 @@ public void start(Model model, TimeValue timeout, ActionListener<Boolean> listen
105111
@Override
106112
public void close() throws IOException {}
107113

114+
protected List<String> chunkInputs(List<String> input, ChunkingSettings chunkingSettings) {
115+
if (chunkingSettings == null) {
116+
return input;
117+
}
118+
List<String> chunkedInputs = new ArrayList<>();
119+
ChunkingStrategy chunkingStrategy = chunkingSettings.getChunkingStrategy();
120+
if (chunkingStrategy == ChunkingStrategy.WORD) {
121+
WordBoundaryChunker chunker = new WordBoundaryChunker();
122+
for (String inputString : input) {
123+
WordBoundaryChunkingSettings wordBoundaryChunkingSettings = (WordBoundaryChunkingSettings) chunkingSettings;
124+
List<WordBoundaryChunker.ChunkOffset> offsets = chunker.chunk(
125+
inputString,
126+
wordBoundaryChunkingSettings.maxChunkSize(),
127+
wordBoundaryChunkingSettings.overlap()
128+
);
129+
for (WordBoundaryChunker.ChunkOffset offset : offsets) {
130+
chunkedInputs.add(inputString.substring(offset.start(), offset.end()));
131+
}
132+
}
133+
} else {
134+
// Won't implement till we need it
135+
throw new UnsupportedOperationException("Test inference service only supports word chunking strategies");
136+
}
137+
138+
return chunkedInputs;
139+
}
140+
108141
public static class TestServiceModel extends Model {
109142

110143
public TestServiceModel(

x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestDenseInferenceServiceExtension.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ public void chunkedInfer(
155155
switch (model.getConfigurations().getTaskType()) {
156156
case ANY, TEXT_EMBEDDING -> {
157157
ServiceSettings modelServiceSettings = model.getServiceSettings();
158-
listener.onResponse(makeChunkedResults(input, modelServiceSettings.dimensions()));
158+
listener.onResponse(makeChunkedResults(input, modelServiceSettings.dimensions(), chunkingSettings));
159159
}
160160
default -> listener.onFailure(
161161
new ElasticsearchStatusException(
@@ -175,6 +175,11 @@ private TextEmbeddingFloatResults makeResults(List<String> input, int dimensions
175175
return new TextEmbeddingFloatResults(embeddings);
176176
}
177177

178+
private List<ChunkedInference> makeChunkedResults(List<String> input, int dimensions, ChunkingSettings chunkingSettings) {
179+
List<String> chunkedInputs = chunkInputs(input, chunkingSettings);
180+
return makeChunkedResults(chunkedInputs, dimensions);
181+
}
182+
178183
private List<ChunkedInference> makeChunkedResults(List<String> input, int dimensions) {
179184
TextEmbeddingFloatResults nonChunkedResults = makeResults(input, dimensions);
180185

x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestSparseInferenceServiceExtension.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import java.util.Map;
4646

4747
public class TestSparseInferenceServiceExtension implements InferenceServiceExtension {
48+
4849
@Override
4950
public List<Factory> getInferenceServiceFactories() {
5051
return List.of(TestInferenceService::new);
@@ -143,7 +144,7 @@ public void chunkedInfer(
143144
ActionListener<List<ChunkedInference>> listener
144145
) {
145146
switch (model.getConfigurations().getTaskType()) {
146-
case ANY, SPARSE_EMBEDDING -> listener.onResponse(makeChunkedResults(input));
147+
case ANY, SPARSE_EMBEDDING -> listener.onResponse(makeChunkedResults(input, chunkingSettings));
147148
default -> listener.onFailure(
148149
new ElasticsearchStatusException(
149150
TaskType.unsupportedTaskTypeErrorMsg(model.getConfigurations().getTaskType(), name()),
@@ -165,6 +166,11 @@ private SparseEmbeddingResults makeResults(List<String> input) {
165166
return new SparseEmbeddingResults(embeddings);
166167
}
167168

169+
private List<ChunkedInference> makeChunkedResults(List<String> input, ChunkingSettings chunkingSettings) {
170+
List<String> chunkedInputs = chunkInputs(input, chunkingSettings);
171+
return makeChunkedResults(chunkedInputs);
172+
}
173+
168174
private List<ChunkedInference> makeChunkedResults(List<String> input) {
169175
List<ChunkedInference> results = new ArrayList<>();
170176
for (int i = 0; i < input.size(); i++) {

x-pack/plugin/inference/src/main/java/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
exports org.elasticsearch.xpack.inference.services;
4343
exports org.elasticsearch.xpack.inference;
4444
exports org.elasticsearch.xpack.inference.action.task;
45+
exports org.elasticsearch.xpack.inference.chunking;
4546
exports org.elasticsearch.xpack.inference.telemetry;
4647

4748
provides org.elasticsearch.features.FeatureSpecification with org.elasticsearch.xpack.inference.InferenceFeatures;

x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/WordBoundaryChunkingSettings.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ public Map<String, Object> asMap() {
5858
return map;
5959
}
6060

61+
public int maxChunkSize() {
62+
return maxChunkSize;
63+
}
64+
65+
public int overlap() {
66+
return overlap;
67+
}
68+
6169
public static WordBoundaryChunkingSettings fromMap(Map<String, Object> map) {
6270
ValidationException validationException = new ValidationException();
6371

x-pack/plugin/inference/src/yamlRestTest/resources/rest-api-spec/test/inference/25_semantic_text_field_mapping_chunking.yml

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ setup:
3737
3838
- do:
3939
indices.create:
40-
index: default-chunking
40+
index: default-chunking-sparse
4141
body:
4242
mappings:
4343
properties:
@@ -49,7 +49,7 @@ setup:
4949

5050
- do:
5151
indices.create:
52-
index: custom-chunking
52+
index: default-chunking-dense
5353
body:
5454
mappings:
5555
properties:
@@ -58,14 +58,26 @@ setup:
5858
inference_field:
5959
type: semantic_text
6060
inference_id: dense-inference-id
61+
62+
- do:
63+
indices.create:
64+
index: custom-chunking-sparse
65+
body:
66+
mappings:
67+
properties:
68+
keyword_field:
69+
type: keyword
70+
inference_field:
71+
type: semantic_text
72+
inference_id: sparse-inference-id
6173
chunking_settings:
6274
strategy: word
6375
max_chunk_size: 10
64-
overlap: 5
76+
overlap: 1
6577

6678
- do:
6779
index:
68-
index: default-chunking
80+
index: default-chunking-sparse
6981
id: doc_1
7082
body:
7183
keyword_field: "default sentence chunking"
@@ -74,7 +86,7 @@ setup:
7486

7587
- do:
7688
index:
77-
index: custom-chunking
89+
index: custom-chunking-sparse
7890
id: doc_2
7991
body:
8092
keyword_field: "custom word chunking"
@@ -86,13 +98,13 @@ setup:
8698

8799
- do:
88100
indices.get_mapping:
89-
index: default-chunking
101+
index: default-chunking-sparse
90102

91103
- is_false: default-chunking.mappings.properties.inference_field.chunking_settings
92104

93105
- do:
94106
indices.get_mapping:
95-
index: custom-chunking
107+
index: custom-chunking-sparse
96108

97109
- match: { "custom-chunking.mappings.properties.inference_field.chunking_settings.strategy": "word" }
98110
- match: { "custom-chunking.mappings.properties.inference_field.chunking_settings.max_chunk_size": 10 }
@@ -103,7 +115,7 @@ setup:
103115

104116
- do:
105117
search:
106-
index: default-chunking
118+
index: default-chunking-sparse
107119
body:
108120
query:
109121
semantic:
@@ -122,7 +134,7 @@ setup:
122134

123135
- do:
124136
search:
125-
index: custom-chunking
137+
index: custom-chunking-sparse
126138
body:
127139
query:
128140
semantic:
@@ -138,5 +150,5 @@ setup:
138150
- match: { hits.hits.0._id: "doc_2" }
139151
- length: { hits.hits.0.highlight.inference_field: 2 }
140152
- match: { hits.hits.0.highlight.inference_field.0: "Elasticsearch is an open source, distributed, RESTful, search engine which is built on top of Lucene internally and enjoys all" }
141-
- match: { hits.hits.0.highlight.inference_field.1: " Lucene internally and enjoys all the features it provides." }
153+
- match: { hits.hits.0.highlight.inference_field.1: " the features it provides." }
142154

0 commit comments

Comments
 (0)