Skip to content

Commit d44d07b

Browse files
committed
Adds IT for Asymmetric Embedding scenario with MLInferenceIngestProcessor
We needed to make sure that a IT existed so that the preset content registry on the processor could work with parametized local models. By providing an IT that uses the asymetric embedding model its proven that the content registry is needed to create the embeddings. In this specific test case I used a ingest pipeline to convert passage embeddings, by simulating the pipeline to save test time. Signed-off-by: Brian Flores <[email protected]>
1 parent f9caf1b commit d44d07b

File tree

2 files changed

+123
-1
lines changed

2 files changed

+123
-1
lines changed

plugin/src/test/java/org/opensearch/ml/rest/RestMLInferenceIngestProcessorIT.java

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package org.opensearch.ml.rest;
77

88
import static org.opensearch.ml.common.MLTask.MODEL_ID_FIELD;
9+
import static org.opensearch.ml.utils.TestData.SENTENCE_TRANSFORMER_MODEL_HASH_VALUE;
910
import static org.opensearch.ml.utils.TestData.SENTENCE_TRANSFORMER_MODEL_URL;
1011
import static org.opensearch.ml.utils.TestHelper.makeRequest;
1112

@@ -28,6 +29,7 @@
2829
import org.opensearch.ml.utils.TestHelper;
2930

3031
import com.google.common.collect.ImmutableList;
32+
import com.jayway.jsonpath.DocumentContext;
3133
import com.jayway.jsonpath.JsonPath;
3234

3335
public class RestMLInferenceIngestProcessorIT extends MLCommonsRestTestCase {
@@ -434,6 +436,110 @@ public void testMLInferenceProcessorLocalModelObjectField() throws Exception {
434436
Assert.assertEquals(0.49191704, (Double) embedding2.get(0), 0.005);
435437
}
436438

439+
public void testMLInferenceIngestProcessor_simulatesIngestPipelineSuccessfully_withAsymmetricEmbeddingModelUsingPassageContentType()
440+
throws Exception {
441+
String taskId = registerModel(TestHelper.toJsonString(registerAsymmetricEmbeddingModelInput()));
442+
waitForTask(taskId, MLTaskState.COMPLETED);
443+
getTask(client(), taskId, response -> {
444+
assertNotNull(response.get(MODEL_ID_FIELD));
445+
this.localModelId = (String) response.get(MODEL_ID_FIELD);
446+
try {
447+
String deployTaskID = deployModel(this.localModelId);
448+
waitForTask(deployTaskID, MLTaskState.COMPLETED);
449+
450+
getModel(client(), this.localModelId, model -> { assertEquals("DEPLOYED", model.get("model_state")); });
451+
} catch (IOException | InterruptedException e) {
452+
throw new RuntimeException(e);
453+
}
454+
});
455+
456+
String asymmetricPipelineName = "asymmetric_embedding_pipeline";
457+
String createPipelineRequestBody = "{\n"
458+
+ " \"description\": \"ingest PASSAGE text and generate a embedding using an asymmetric model\",\n"
459+
+ " \"processors\": [\n"
460+
+ " {\n"
461+
+ " \"ml_inference\": {\n"
462+
+ "\n"
463+
+ " \"model_input\": \"{\\\"text_docs\\\":[\\\"${input_map.text_docs}\\\"],\\\"target_response\\\":[\\\"sentence_embedding\\\"],\\\"parameters\\\":{\\\"content_type\\\":\\\"passage\\\"}}\",\n"
464+
+ " \"function_name\": \"text_embedding\",\n"
465+
+ " \"model_id\": \""
466+
+ this.localModelId
467+
+ "\",\n"
468+
+ " \"input_map\": [\n"
469+
+ " {\n"
470+
+ " \"text_docs\": \"description\"\n"
471+
+ " }\n"
472+
+ " ],\n"
473+
+ " \"output_map\": [\n"
474+
+ " {\n"
475+
+ "\n"
476+
+ " "
477+
+ " \"fact_embedding\": \"$.inference_results[0].output[0].data\"\n"
478+
+ " }\n"
479+
+ " ]\n"
480+
+ " }\n"
481+
+ " }\n"
482+
+ " ]\n"
483+
+ "}";
484+
485+
createPipelineProcessor(createPipelineRequestBody, asymmetricPipelineName);
486+
String sampleDocuments = "{\n"
487+
+ " \"docs\": [\n"
488+
+ " {\n"
489+
+ " \"_index\": \"my-index\",\n"
490+
+ " \"_id\": \"1\",\n"
491+
+ " \"_source\": {\n"
492+
+ " \"title\": \"Central Park\",\n"
493+
+ " \"description\": \"A large public park in the heart of New York City, offering a wide range of recreational activities.\"\n"
494+
+ " }\n"
495+
+ " },\n"
496+
+ " {\n"
497+
+ " \"_index\": \"my-index\",\n"
498+
+ " \"_id\": \"2\",\n"
499+
+ " \"_source\": {\n"
500+
+ " \"title\": \"Empire State Building\",\n"
501+
+ " \"description\": \"An iconic skyscraper in New York City offering breathtaking views from its observation deck.\"\n"
502+
+ " }\n"
503+
+ " }\n"
504+
+ " ]\n"
505+
+ "}\n";
506+
507+
Map simulateResponseDocuments = simulateIngestPipeline(asymmetricPipelineName, sampleDocuments);
508+
509+
DocumentContext documents = JsonPath.parse(simulateResponseDocuments);
510+
511+
List centralParkFactEmbedding = documents.read("docs.[0].*._source.fact_embedding.*");
512+
assertEquals(768, centralParkFactEmbedding.size());
513+
Assert.assertEquals(0.5137818, (Double) centralParkFactEmbedding.get(0), 0.005);
514+
515+
List empireStateBuildingFactEmbedding = documents.read("docs.[1].*._source.fact_embedding.*");
516+
assertEquals(768, empireStateBuildingFactEmbedding.size());
517+
Assert.assertEquals(0.4493039, (Double) empireStateBuildingFactEmbedding.get(0), 0.005);
518+
}
519+
520+
private MLRegisterModelInput registerAsymmetricEmbeddingModelInput() {
521+
MLModelConfig modelConfig = TextEmbeddingModelConfig
522+
.builder()
523+
.modelType("bert")
524+
.frameworkType(TextEmbeddingModelConfig.FrameworkType.SENTENCE_TRANSFORMERS)
525+
.embeddingDimension(768)
526+
.queryPrefix("query >>")
527+
.passagePrefix("passage >> ")
528+
.build();
529+
530+
return MLRegisterModelInput
531+
.builder()
532+
.modelName("test_model_name")
533+
.version("1.0.0")
534+
.functionName(FunctionName.TEXT_EMBEDDING)
535+
.modelFormat(MLModelFormat.TORCH_SCRIPT)
536+
.modelConfig(modelConfig)
537+
.url(SENTENCE_TRANSFORMER_MODEL_URL)
538+
.deployModel(false)
539+
.hashValue(SENTENCE_TRANSFORMER_MODEL_HASH_VALUE)
540+
.build();
541+
}
542+
437543
// TODO: add tests for other local model types such as sparse/cross encoders
438544
public void testMLInferenceProcessorLocalModelNestedField() throws Exception {
439545

@@ -560,6 +666,21 @@ protected void createPipelineProcessor(String requestBody, final String pipeline
560666

561667
}
562668

669+
protected Map simulateIngestPipeline(String pipelineName, String sampleDocuments) throws IOException {
670+
Response ingestionResponse = TestHelper
671+
.makeRequest(
672+
client(),
673+
"POST",
674+
"/_ingest/pipeline/" + pipelineName + "/_simulate",
675+
null,
676+
sampleDocuments,
677+
ImmutableList.of(new BasicHeader(HttpHeaders.USER_AGENT, ""))
678+
);
679+
assertEquals(200, ingestionResponse.getStatusLine().getStatusCode());
680+
681+
return parseResponseToMap(ingestionResponse);
682+
}
683+
563684
protected void createIndex(String indexName, String requestBody) throws Exception {
564685
Response response = makeRequest(
565686
client(),
@@ -602,7 +723,7 @@ protected MLRegisterModelInput registerModelInput() throws IOException, Interrup
602723
.modelConfig(modelConfig)
603724
.url(SENTENCE_TRANSFORMER_MODEL_URL)
604725
.deployModel(false)
605-
.hashValue("e13b74006290a9d0f58c1376f9629d4ebc05a0f9385f40db837452b167ae9021")
726+
.hashValue(SENTENCE_TRANSFORMER_MODEL_HASH_VALUE)
606727
.build();
607728
}
608729

plugin/src/test/java/org/opensearch/ml/utils/TestData.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public class TestData {
3030
"https://github.com/opensearch-project/ml-commons/blob/2.x/ml-algorithms/src/test/resources/org/opensearch/ml/engine/algorithms/text_embedding/all-MiniLM-L6-v2_torchscript_huggingface.zip?raw=true";
3131
public static final String SENTENCE_TRANSFORMER_MODEL_URL =
3232
"https://github.com/opensearch-project/ml-commons/blob/2.x/ml-algorithms/src/test/resources/org/opensearch/ml/engine/algorithms/text_embedding/traced_small_model.zip?raw=true";
33+
public static final String SENTENCE_TRANSFORMER_MODEL_HASH_VALUE = "e13b74006290a9d0f58c1376f9629d4ebc05a0f9385f40db837452b167ae9021";
3334
public static final String TIME_FIELD = "timestamp";
3435
public static final String HUGGINGFACE_TRANSFORMER_MODEL_HASH_VALUE =
3536
"e13b74006290a9d0f58c1376f9629d4ebc05a0f9385f40db837452b167ae9021";

0 commit comments

Comments
 (0)