Skip to content

Commit

Permalink
Add BWC tests for Lucene Engine (#2313)
Browse files Browse the repository at this point in the history
Added backward compatibility tests for Lucene engine

Signed-off-by: Sahil Buddharaju <[email protected]>
Co-authored-by: Sahil Buddharaju <[email protected]>
  • Loading branch information
buddharajusahil and Sahil Buddharaju authored Dec 16, 2024
1 parent a5fb171 commit f50a8f5
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
### Maintenance
* Select index settings based on cluster version[2236](https://github.com/opensearch-project/k-NN/pull/2236)
* Added null checks for fieldInfo in ExactSearcher to avoid NPE while running exact search for segments with no vector field (#2278)[https://github.com/opensearch-project/k-NN/pull/2278]
* Added Lucene BWC tests (#2313)[https://github.com/opensearch-project/k-NN/pull/2313]
* Upgrade jsonpath from 2.8.0 to 2.9.0[2325](https://github.com/opensearch-project/k-NN/pull/2325)
### Refactoring
33 changes: 32 additions & 1 deletion qa/restart-upgrade/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,21 @@ testClusters {
excludeTestsMatching "org.opensearch.knn.bwc.IndexingIT.testEmptyParametersOnUpgrade"
}
}


if (knn_bwc_version.startsWith("1.") ||
knn_bwc_version.startsWith("2.0.") ||
knn_bwc_version.startsWith("2.1.") ||
knn_bwc_version.startsWith("2.2.") ||
knn_bwc_version.startsWith("2.3.") ||
knn_bwc_version.startsWith("2.4") ||
knn_bwc_version.startsWith("2.5.") ||
knn_bwc_version.startsWith("2.6.") ||
knn_bwc_version.startsWith("2.7.") ||
knn_bwc_version.startsWith("2.8.")) {
filter {
excludeTestsMatching "org.opensearch.knn.bwc.IndexingIT.testKNNIndexLuceneByteVector"
}
}
if (knn_bwc_version.startsWith("1.") ||
knn_bwc_version.startsWith("2.0.") ||
knn_bwc_version.startsWith("2.1.") ||
Expand All @@ -86,10 +100,12 @@ testClusters {
knn_bwc_version.startsWith("2.14.") ||
knn_bwc_version.startsWith("2.15.")) {
filter {
excludeTestsMatching "org.opensearch.knn.bwc.IndexingIT.testKNNIndexLuceneQuantization"
excludeTestsMatching "org.opensearch.knn.bwc.IndexingIT.testKNNIndexBinaryForceMerge"
}
}


if (versionsBelow2_3.any {knn_bwc_version.startsWith(it) }) {
filter {
excludeTestsMatching "org.opensearch.knn.bwc.QueryANNIT.testQueryOnLuceneIndex"
Expand Down Expand Up @@ -141,6 +157,20 @@ testClusters {
}
}

if (knn_bwc_version.startsWith("1.") ||
knn_bwc_version.startsWith("2.0.") ||
knn_bwc_version.startsWith("2.1.") ||
knn_bwc_version.startsWith("2.2.") ||
knn_bwc_version.startsWith("2.3.") ||
knn_bwc_version.startsWith("2.4") ||
knn_bwc_version.startsWith("2.5.") ||
knn_bwc_version.startsWith("2.6.") ||
knn_bwc_version.startsWith("2.7.") ||
knn_bwc_version.startsWith("2.8.")) {
filter {
excludeTestsMatching "org.opensearch.knn.bwc.IndexingIT.testKNNIndexLuceneByteVector"
}
}
if (knn_bwc_version.startsWith("1.") ||
knn_bwc_version.startsWith("2.0.") ||
knn_bwc_version.startsWith("2.1.") ||
Expand All @@ -159,6 +189,7 @@ testClusters {
knn_bwc_version.startsWith("2.14.") ||
knn_bwc_version.startsWith("2.15.")) {
filter {
excludeTestsMatching "org.opensearch.knn.bwc.IndexingIT.testKNNIndexLuceneQuantization"
excludeTestsMatching "org.opensearch.knn.bwc.IndexingIT.testKNNIndexBinaryForceMerge"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@

package org.opensearch.knn.bwc;

import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.junit.Assert;
import org.opensearch.client.Response;
import org.opensearch.common.settings.Settings;
import org.opensearch.common.xcontent.XContentFactory;
import org.opensearch.knn.KNNResult;
import org.opensearch.knn.index.KNNSettings;
import org.opensearch.knn.index.SpaceType;
import org.opensearch.knn.index.VectorDataType;
import org.opensearch.knn.index.engine.KNNEngine;
import org.opensearch.knn.index.query.KNNQueryBuilder;

import java.util.List;
import java.util.Map;
Expand All @@ -32,6 +36,8 @@
import static org.opensearch.knn.common.KNNConstants.METHOD_PARAMETER_EF_SEARCH;
import static org.opensearch.knn.common.KNNConstants.METHOD_PARAMETER_M;
import static org.opensearch.knn.common.KNNConstants.METHOD_PARAMETER_SPACE_TYPE;
import static org.opensearch.knn.common.KNNConstants.METHOD_ENCODER_PARAMETER;
import static org.opensearch.knn.common.KNNConstants.ENCODER_SQ;
import static org.opensearch.knn.common.KNNConstants.NAME;
import static org.opensearch.knn.common.KNNConstants.PARAMETERS;

Expand Down Expand Up @@ -126,6 +132,85 @@ public void testKNNIndexLuceneForceMerge() throws Exception {
}
}

public void testKNNIndexLuceneByteVector() throws Exception {
waitForClusterHealthGreen(NODES_BWC_CLUSTER);

if (isRunningAgainstOldCluster()) {
createKnnIndex(
testIndex,
getKNNDefaultIndexSettings(),
createKnnIndexMapping(TEST_FIELD, DIMENSIONS, METHOD_HNSW, LUCENE_NAME, SpaceType.L2.getValue(), true, VectorDataType.BYTE)
);
addKNNByteDocs(testIndex, TEST_FIELD, DIMENSIONS, DOC_ID, 50);
// Flush to ensure that index is not re-indexed when node comes back up
flush(testIndex, true);
validateKNNSearch(testIndex, TEST_FIELD, DIMENSIONS, 50, 5);
} else {
validateKNNSearch(testIndex, TEST_FIELD, DIMENSIONS, 50, 5);
addKNNDocs(testIndex, TEST_FIELD, DIMENSIONS, 50, 25);
validateKNNSearch(testIndex, TEST_FIELD, DIMENSIONS, 75, 5);
deleteKNNIndex(testIndex);
}
}

public void testKNNIndexLuceneQuantization() throws Exception {
waitForClusterHealthGreen(NODES_BWC_CLUSTER);
int k = 4;
int dimension = 2;

if (isRunningAgainstOldCluster()) {
String mapping = XContentFactory.jsonBuilder()
.startObject()
.startObject("properties")
.startObject(TEST_FIELD)
.field(VECTOR_TYPE, KNN_VECTOR)
.field(DIMENSION, dimension)
.startObject(KNN_METHOD)
.field(NAME, METHOD_HNSW)
.field(METHOD_PARAMETER_SPACE_TYPE, SpaceType.INNER_PRODUCT.getValue())
.field(KNN_ENGINE, LUCENE_NAME)
.startObject(PARAMETERS)
.startObject(METHOD_ENCODER_PARAMETER)
.field(NAME, ENCODER_SQ)
.endObject()
.field(METHOD_PARAMETER_EF_CONSTRUCTION, 256)
.field(METHOD_PARAMETER_M, 16)
.endObject()
.endObject()
.endObject()
.endObject()
.endObject()
.toString();
createKnnIndex(testIndex, getKNNDefaultIndexSettings(), mapping);

Float[] vector1 = { -10.6f, 25.48f };
Float[] vector2 = { -10.8f, 25.48f };
Float[] vector3 = { -11.0f, 25.48f };
Float[] vector4 = { -11.2f, 25.48f };
addKnnDoc(testIndex, "1", TEST_FIELD, vector1);
addKnnDoc(testIndex, "2", TEST_FIELD, vector2);
addKnnDoc(testIndex, "3", TEST_FIELD, vector3);
addKnnDoc(testIndex, "4", TEST_FIELD, vector4);

float[] queryVector = { -10.5f, 25.48f };
Response searchResponse = searchKNNIndex(testIndex, new KNNQueryBuilder(TEST_FIELD, queryVector, k), k);
List<KNNResult> results = parseSearchResponse(EntityUtils.toString(searchResponse.getEntity()), TEST_FIELD);
assertEquals(k, results.size());
for (int i = 0; i < k; i++) {
assertEquals(k - i, Integer.parseInt(results.get(i).getDocId()));
}
} else {
float[] queryVector = { -10.5f, 25.48f };
Response searchResponse = searchKNNIndex(testIndex, new KNNQueryBuilder(TEST_FIELD, queryVector, k), k);
List<KNNResult> results = parseSearchResponse(EntityUtils.toString(searchResponse.getEntity()), TEST_FIELD);
assertEquals(k, results.size());
for (int i = 0; i < k; i++) {
assertEquals(k - i, Integer.parseInt(results.get(i).getDocId()));
}
deleteKNNIndex(testIndex);
}
}

// Ensure bwc works for binary force merge
public void testKNNIndexBinaryForceMerge() throws Exception {
int dimension = 40;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public class IndexingIT extends AbstractRollingUpgradeTestCase {

private static final String ALGO = "hnsw";

private static final String ENGINE = "faiss";
private static final String FAISS_NAME = "faiss";
private static final String LUCENE_NAME = "lucene";

public void testKNNDefaultIndexSettings() throws Exception {
waitForClusterHealthGreen(NODES_BWC_CLUSTER);
Expand Down Expand Up @@ -91,7 +92,7 @@ public void testKNNIndexCreation_withMethodMapper() throws Exception {
final String upgradedIndex = testIndex + "upgraded";
switch (getClusterType()) {
case OLD:
createKnnIndex(testIndex, getKNNDefaultIndexSettings(), createKnnIndexMapping(TEST_FIELD, DIMENSIONS, ALGO, ENGINE));
createKnnIndex(testIndex, getKNNDefaultIndexSettings(), createKnnIndexMapping(TEST_FIELD, DIMENSIONS, ALGO, FAISS_NAME));
int docIdOld = 0;
addKNNDocs(testIndex, TEST_FIELD, DIMENSIONS, docIdOld, NUM_DOCS);
break;
Expand All @@ -101,22 +102,72 @@ public void testKNNIndexCreation_withMethodMapper() throws Exception {
createKnnIndex(
firstMixRoundIndex,
getKNNDefaultIndexSettings(),
createKnnIndexMapping(TEST_FIELD, DIMENSIONS, ALGO, ENGINE)
createKnnIndexMapping(TEST_FIELD, DIMENSIONS, ALGO, FAISS_NAME)
);
addKNNDocs(firstMixRoundIndex, TEST_FIELD, DIMENSIONS, docIdOld, NUM_DOCS);
} else {
docIdOld = 0;
createKnnIndex(
otherMixRoundIndex,
getKNNDefaultIndexSettings(),
createKnnIndexMapping(TEST_FIELD, DIMENSIONS, ALGO, ENGINE)
createKnnIndexMapping(TEST_FIELD, DIMENSIONS, ALGO, FAISS_NAME)
);
addKNNDocs(otherMixRoundIndex, TEST_FIELD, DIMENSIONS, docIdOld, NUM_DOCS);
}
break;
case UPGRADED:
docIdOld = 0;
createKnnIndex(upgradedIndex, getKNNDefaultIndexSettings(), createKnnIndexMapping(TEST_FIELD, DIMENSIONS, ALGO, ENGINE));
createKnnIndex(
upgradedIndex,
getKNNDefaultIndexSettings(),
createKnnIndexMapping(TEST_FIELD, DIMENSIONS, ALGO, FAISS_NAME)
);
addKNNDocs(upgradedIndex, TEST_FIELD, DIMENSIONS, docIdOld, NUM_DOCS);

deleteKNNIndex(testIndex);
deleteKNNIndex(firstMixRoundIndex);
deleteKNNIndex(otherMixRoundIndex);
deleteKNNIndex(upgradedIndex);
}
}

public void testKNNLuceneIndexCreation_withMethodMapper() throws Exception {
waitForClusterHealthGreen(NODES_BWC_CLUSTER);
final String firstMixRoundIndex = testIndex + "first-mix-round";
final String otherMixRoundIndex = testIndex + "other-mix-round";
final String upgradedIndex = testIndex + "upgraded";
switch (getClusterType()) {
case OLD:
createKnnIndex(testIndex, getKNNDefaultIndexSettings(), createKnnIndexMapping(TEST_FIELD, DIMENSIONS, ALGO, LUCENE_NAME));
int docIdOld = 0;
addKNNDocs(testIndex, TEST_FIELD, DIMENSIONS, docIdOld, NUM_DOCS);
break;
case MIXED:
if (isFirstMixedRound()) {
docIdOld = 0;
createKnnIndex(
firstMixRoundIndex,
getKNNDefaultIndexSettings(),
createKnnIndexMapping(TEST_FIELD, DIMENSIONS, ALGO, LUCENE_NAME)
);
addKNNDocs(firstMixRoundIndex, TEST_FIELD, DIMENSIONS, docIdOld, NUM_DOCS);
} else {
docIdOld = 0;
createKnnIndex(
otherMixRoundIndex,
getKNNDefaultIndexSettings(),
createKnnIndexMapping(TEST_FIELD, DIMENSIONS, ALGO, LUCENE_NAME)
);
addKNNDocs(otherMixRoundIndex, TEST_FIELD, DIMENSIONS, docIdOld, NUM_DOCS);
}
break;
case UPGRADED:
docIdOld = 0;
createKnnIndex(
upgradedIndex,
getKNNDefaultIndexSettings(),
createKnnIndexMapping(TEST_FIELD, DIMENSIONS, ALGO, LUCENE_NAME)
);
addKNNDocs(upgradedIndex, TEST_FIELD, DIMENSIONS, docIdOld, NUM_DOCS);

deleteKNNIndex(testIndex);
Expand Down

0 comments on commit f50a8f5

Please sign in to comment.