Skip to content
Open
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
12 changes: 0 additions & 12 deletions src/main/java/ru/rt/restream/reindexer/Reindexer.java
Original file line number Diff line number Diff line change
Expand Up @@ -282,28 +282,16 @@ public <T> Query<T> query(String namespaceName, Class<T> clazz) {
return new Query<>(this, namespace, null);
}

/**
* ONLY FOR TEST PURPOSES!
*/
@Deprecated
public void addIndex(String namespaceName, ReindexerIndex index) {
IndexDefinition indexDefinition = IndexDefinition.fromIndex(index);
binding.addIndex(namespaceName, indexDefinition);
}

/**
* ONLY FOR TEST PURPOSES!
*/
@Deprecated
public void updateIndex(String namespaceName, ReindexerIndex index) {
IndexDefinition indexDefinition = IndexDefinition.fromIndex(index);
binding.updateIndex(namespaceName, indexDefinition);
}

/**
* ONLY FOR TEST PURPOSES!
*/
@Deprecated
public void dropIndex(String namespaceName, String indexName) {
binding.dropIndex(namespaceName, indexName);
}
Expand Down
36 changes: 36 additions & 0 deletions src/main/java/ru/rt/restream/reindexer/annotations/Hnsw.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,40 @@
*/
boolean multithreading() default false;

/**
* Optional quantization configuration for HNSW index.
*
* <p>When {@code quantizationConfig.quantizationType} is empty, the whole block is ignored.
*
* <p>Currently supported type: {@code scalar_quantization_8_bit}.
*/
QuantizationConfig quantizationConfig() default @QuantizationConfig;

/**
* Nested annotation representing {@code quantization_config} block.
*/
@interface QuantizationConfig {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Как вариант - вынести в отдельный класс.

Также, возможно, немного поменял бы имена.
Чтобы вместо quantizationConfig = @Hnsw.QuantizationConfig(quantizationType = "scalar_quantization_8_bit", quantile = 0.987f, sampleSize = 3000, quantizationThreshold = 5000)
было что-то вроде quantization = @Quantization(type = "scalar_quantization_8_bit", quantile = 0.987f, sampleSize = 3000, threshold = 5000)

Правда, тогда будет рассинхрон с HnswConfig, а тот менять нельзя, т.к. имена полей сериализуются для RX. Пожалуй, пусть остается единообразно.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ну на ваше усмотрение) как будто перекладка в HSNWConfig в src/main/java/ru/rt/restream/reindexer/vector/HnswConfigs.java позволяет использовать другие имена в аннотации. Так что, как удобнее.

/**
* Quantization type.
*
* <p>Currently supported: {@code scalar_quantization_8_bit}.
*/
String quantizationType() default "";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если в будущем число вариантов квантизации будет больше одного, но останется небольшим - может, сразу сделать enum? Как Metric. Чтобы нельзя было присвоить неподходящее значение? Хотя, конечно, при расширении списка потребуется модификация кода коннектора, что неудобно...

Если это единственный вариант, и в будущем останется единственным - может, сделать булевым полем? isScalarQuantization8bit.

Copy link
Copy Markdown
Author

@maximbogatyrev maximbogatyrev Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ну у нас пока планов нет на добавление нового типа квантования. В ядре проверка захардкожена на строку "scalar_quantization_8_bit". Главное, что если в этом поле что-то приходит, то именно это значение. Так что, опять же, как удобнее

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bool точно не стоит, так как в перспективе их будет несколько


/**
* Quantile for scalar quantization.
*/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Добавить бы в доку допустимые значения.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ну, разве что вот в таком виде, возможно урезанном:
Quantile used to determine the clipping range of vector components before quantization. Allowed values range from 0.95 to 1.0. The default value is computed automatically based on the dimensionality of vectors in the index. It is recommended to change this parameter only if the distribution of vector component values is known and additional search quality tuning is required, for example to achieve the expected recall

float quantile() default -1.0f;

/**
* Sample size for estimating quantile(s).
*/
int sampleSize() default 20_000;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Допустимые значения? Отрицательное можно?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

целые знаковые, от 1 до UINT64_MAX


/**
* Minimal number of points in the index required to enable quantization.
*/
int quantizationThreshold() default 100_000;
}

}
43 changes: 43 additions & 0 deletions src/main/java/ru/rt/restream/reindexer/vector/HnswConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,47 @@ public class HnswConfig implements IndexConfig {
* Enable multithreading insert mode.
*/
private int multithreading;

/**
* Optional quantization configuration for HNSW index.
*
* <p>
* When this value is {@code null} the {@code quantization_config} block is not
* serialized.
*/
private QuantizationConfig quantizationConfig;

@Setter
@Getter
@EqualsAndHashCode
@NoArgsConstructor(access = AccessLevel.PACKAGE)
public static class QuantizationConfig {
/**
* Quantization type.
*
* <p>
* Currently supported: {@code scalar_quantization_8_bit}.
*/
private String quantizationType;

/**
* Quantile for scalar quantization.
*
* <p>
* If this field is {@code null}, quantile is expected to be computed
* automatically
* by Reindexer.
*/
private Float quantile;

/**
* Sample size for estimating quantile(s).
*/
private int sampleSize;

/**
* Minimal number of samples/points required to enable quantization.
*/
private int quantizationThreshold;
}
}
27 changes: 27 additions & 0 deletions src/main/java/ru/rt/restream/reindexer/vector/HnswConfigs.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public class HnswConfigs {
new IllegalArgumentException("HNSW index should have 'm' parameter in range [2, 128]");
public static final IllegalArgumentException EF_CONSTRUCTION_NOT_IN_RANGE_EX =
new IllegalArgumentException("HNSW index should have 'efConstruction' parameter in range [4, 1024]");
public static final IllegalArgumentException QUANTIZATION_TYPE_NOT_SUPPORTED_EX =
new IllegalArgumentException("Only 'scalar_quantization_8_bit' is supported for HNSW quantization_config.");
public static final IllegalArgumentException QUANTILE_OUT_OF_RANGE_EX =
new IllegalArgumentException("Quantile for scalar quantization must be in range [0.95, 1.0].");
private static final float QUANTILE_UNSET = -1.0f;

public static HnswConfig of(Hnsw annotation) {
if (annotation.metric() == null) {
Expand All @@ -52,6 +57,28 @@ public static HnswConfig of(Hnsw annotation) {
config.setM(annotation.m());
config.setEfConstruction(annotation.efConstruction());
config.setMultithreading(annotation.multithreading() ? 1 : 0);

String quantizationType = annotation.quantizationConfig().quantizationType();
float quantile = annotation.quantizationConfig().quantile();
int sampleSize = annotation.quantizationConfig().sampleSize();
int quantizationThreshold = annotation.quantizationConfig().quantizationThreshold();

if (quantizationType != null && !quantizationType.isEmpty()) {
if (!"scalar_quantization_8_bit".equals(quantizationType)) {
throw QUANTIZATION_TYPE_NOT_SUPPORTED_EX;
}
HnswConfig.QuantizationConfig quantizationConfig = new HnswConfig.QuantizationConfig();
quantizationConfig.setQuantizationType(quantizationType);
if (quantile != QUANTILE_UNSET) {
if (quantile < 0.95f || quantile > 1.0f) {
throw QUANTILE_OUT_OF_RANGE_EX;
}
quantizationConfig.setQuantile(quantile);
}
quantizationConfig.setSampleSize(sampleSize);
quantizationConfig.setQuantizationThreshold(quantizationThreshold);
config.setQuantizationConfig(quantizationConfig);
}
return config;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2020 Restream
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ru.rt.restream.reindexer.connector;

import ru.rt.restream.category.BuiltinTest;

@BuiltinTest
public class BuiltinHnswQuantizationConfigUpdateTest extends HnswQuantizationConfigUpdateTest {
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2020 Restream
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ru.rt.restream.reindexer.connector;

import ru.rt.restream.category.CprotoTest;

@CprotoTest
public class CprotoHnswQuantizationConfigUpdateTest extends HnswQuantizationConfigUpdateTest {
}

Loading
Loading