Skip to content

Commit 86398a3

Browse files
Introduce compression and mode mapping parms (#2019) (#2029)
Introduces new params for mapping and training, called compression_level and mode. These parameters are high level parameters that give the plugin a hint as to what the user wants to configure their system like without exposing algorithmic details. This change just adds these parameters to the plugin as noops. In future change, we will add the functionality for parameter resolution. Along with this, I added a class to more easily manage the original parameters that a user passes. This will help ensure our mapper maintains good compatibility. Signed-off-by: John Mazanec <jmazane@amazon.com> (cherry picked from commit 920c819)
1 parent 5c00dba commit 86398a3

39 files changed

+1491
-258
lines changed

src/main/java/org/opensearch/knn/common/KNNConstants.java

+4
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ public class KNNConstants {
7171
public static final String VECTOR_DATA_TYPE_FIELD = "data_type";
7272
public static final String MODEL_VECTOR_DATA_TYPE_KEY = VECTOR_DATA_TYPE_FIELD;
7373
public static final VectorDataType DEFAULT_VECTOR_DATA_TYPE_FIELD = VectorDataType.FLOAT;
74+
public static final String MINIMAL_MODE_AND_COMPRESSION_FEATURE = "mode_and_compression_feature";
7475

7576
public static final String RADIAL_SEARCH_KEY = "radial_search";
7677

@@ -149,4 +150,7 @@ public class KNNConstants {
149150
public static final Float DEFAULT_LUCENE_RADIAL_SEARCH_TRAVERSAL_SIMILARITY_RATIO = 0.95f;
150151
public static final String MIN_SCORE = "min_score";
151152
public static final String MAX_DISTANCE = "max_distance";
153+
154+
public static final String MODE_PARAMETER = "mode";
155+
public static final String COMPRESSION_LEVEL_PARAMETER = "compression_level";
152156
}

src/main/java/org/opensearch/knn/index/engine/KNNMethodConfigContext.java

+2-22
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@
77

88
import lombok.AllArgsConstructor;
99
import lombok.Builder;
10+
import lombok.EqualsAndHashCode;
1011
import lombok.Getter;
1112
import lombok.Setter;
12-
import org.apache.commons.lang.builder.EqualsBuilder;
13-
import org.apache.commons.lang.builder.HashCodeBuilder;
1413
import org.opensearch.Version;
1514
import org.opensearch.knn.index.VectorDataType;
1615

@@ -23,29 +22,10 @@
2322
@Getter
2423
@Builder
2524
@AllArgsConstructor
25+
@EqualsAndHashCode
2626
public final class KNNMethodConfigContext {
2727
private VectorDataType vectorDataType;
2828
private Integer dimension;
2929
private Version versionCreated;
30-
31-
@Override
32-
public boolean equals(Object obj) {
33-
if (this == obj) return true;
34-
if (obj == null || getClass() != obj.getClass()) return false;
35-
KNNMethodConfigContext other = (KNNMethodConfigContext) obj;
36-
37-
EqualsBuilder equalsBuilder = new EqualsBuilder();
38-
equalsBuilder.append(vectorDataType, other.vectorDataType);
39-
equalsBuilder.append(dimension, other.dimension);
40-
equalsBuilder.append(versionCreated, other.versionCreated);
41-
42-
return equalsBuilder.isEquals();
43-
}
44-
45-
@Override
46-
public int hashCode() {
47-
return new HashCodeBuilder().append(vectorDataType).append(dimension).append(versionCreated).toHashCode();
48-
}
49-
5030
public static final KNNMethodConfigContext EMPTY = KNNMethodConfigContext.builder().build();
5131
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.opensearch.knn.index.mapper;
7+
8+
import lombok.AllArgsConstructor;
9+
import lombok.Getter;
10+
import org.opensearch.core.common.Strings;
11+
12+
import java.util.Arrays;
13+
import java.util.Locale;
14+
import java.util.stream.Collectors;
15+
16+
/**
17+
* Enum representing the compression level for float vectors. Compression in this sense refers to compressing a
18+
* full precision value into a smaller number of bits. For instance. "16x" compression would mean that 2 bits would
19+
* need to be used to represent a 32-bit floating point number.
20+
*/
21+
@AllArgsConstructor
22+
public enum CompressionLevel {
23+
NOT_CONFIGURED(-1, ""),
24+
x1(1, "1x"),
25+
x2(2, "2x"),
26+
x4(4, "4x"),
27+
x8(8, "8x"),
28+
x16(16, "16x"),
29+
x32(32, "32x");
30+
31+
// Internally, an empty string is easier to deal with them null. However, from the mapping,
32+
// we do not want users to pass in the empty string and instead want null. So we make the conversion herex
33+
static final String[] NAMES_ARRAY = Arrays.stream(CompressionLevel.values())
34+
.map(compressionLevel -> compressionLevel == NOT_CONFIGURED ? null : compressionLevel.getName())
35+
.collect(Collectors.toList())
36+
.toArray(new String[0]);
37+
38+
/**
39+
* Default is set to 1x and is a noop
40+
*/
41+
private static final CompressionLevel DEFAULT = x1;
42+
43+
/**
44+
* Get the compression level from a string representation. The format for the string should be "Nx", where N is
45+
* the factor by which compression should take place
46+
*
47+
* @param name String representation of the compression level
48+
* @return CompressionLevel enum value
49+
*/
50+
public static CompressionLevel fromName(String name) {
51+
if (Strings.isEmpty(name)) {
52+
return NOT_CONFIGURED;
53+
}
54+
for (CompressionLevel config : CompressionLevel.values()) {
55+
if (config.getName() != null && config.getName().equals(name)) {
56+
return config;
57+
}
58+
}
59+
throw new IllegalArgumentException(String.format(Locale.ROOT, "Invalid compression level: \"[%s]\"", name));
60+
}
61+
62+
private final int compressionLevel;
63+
@Getter
64+
private final String name;
65+
66+
/**
67+
* Gets the number of bits used to represent a float in order to achieve this compression. For instance, for
68+
* 32x compression, each float would need to be encoded in a single bit.
69+
*
70+
* @return number of bits to represent a float at this compression level
71+
*/
72+
public int numBitsForFloat32() {
73+
if (this == NOT_CONFIGURED) {
74+
return DEFAULT.numBitsForFloat32();
75+
}
76+
77+
return (Float.BYTES * Byte.SIZE) / compressionLevel;
78+
}
79+
80+
/**
81+
* Utility method that checks if compression is configured.
82+
*
83+
* @param compressionLevel Compression to check
84+
* @return true if compression is configured, false otherwise
85+
*/
86+
public static boolean isConfigured(CompressionLevel compressionLevel) {
87+
return compressionLevel != null && compressionLevel != NOT_CONFIGURED;
88+
}
89+
}

src/main/java/org/opensearch/knn/index/mapper/FlatVectorFieldMapper.java

+17-4
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ public static FlatVectorFieldMapper createFieldMapper(
3131
CopyTo copyTo,
3232
Explicit<Boolean> ignoreMalformed,
3333
boolean stored,
34-
boolean hasDocValues
34+
boolean hasDocValues,
35+
OriginalMappingParameters originalMappingParameters
3536
) {
3637
final KNNVectorFieldType mappedFieldType = new KNNVectorFieldType(
3738
fullname,
@@ -47,7 +48,8 @@ public static FlatVectorFieldMapper createFieldMapper(
4748
ignoreMalformed,
4849
stored,
4950
hasDocValues,
50-
knnMethodConfigContext.getVersionCreated()
51+
knnMethodConfigContext.getVersionCreated(),
52+
originalMappingParameters
5153
);
5254
}
5355

@@ -59,9 +61,20 @@ private FlatVectorFieldMapper(
5961
Explicit<Boolean> ignoreMalformed,
6062
boolean stored,
6163
boolean hasDocValues,
62-
Version indexCreatedVersion
64+
Version indexCreatedVersion,
65+
OriginalMappingParameters originalMappingParameters
6366
) {
64-
super(simpleName, mappedFieldType, multiFields, copyTo, ignoreMalformed, stored, hasDocValues, indexCreatedVersion, null);
67+
super(
68+
simpleName,
69+
mappedFieldType,
70+
multiFields,
71+
copyTo,
72+
ignoreMalformed,
73+
stored,
74+
hasDocValues,
75+
indexCreatedVersion,
76+
originalMappingParameters
77+
);
6578
// setting it explicitly false here to ensure that when flatmapper is used Lucene based Vector field is not created.
6679
this.useLuceneBasedVectorField = false;
6780
this.perDimensionValidator = selectPerDimensionValidator(vectorDataType);

0 commit comments

Comments
 (0)