Brute-force
Этот векторный индекс выполняет поиск простым перебором. Максимально быстрая вставка, но медленный поиск. Реализован на основе brute-force-индекса из библиотеки hnswlib.
Параметры конфигурации
Для brute-force-индексов опционально можно задавать начальный размер start_size,
который помогает избежать переаллокаций.
Оптимальное значение равно размеру полностью заполненного индекса. Значение может быть настолько большим, насколько хватит ресурсов памяти. При установке ожидаемого размера индекс будет работать эффективнее, чем со значением по умолчанию.
Слишком большой размер приведет к перерасходу памяти, слишком маленький размер приведет к замедлению вставок.
Минимальное значение и значение по умолчанию равны 1000.
Также для векторного индекса можно добавить опциональный параметр radius для фильтрации выдачи по умолчанию. Если в запросе будет передан параметр radius, то для фильтрации выдачи будет использовано переданное значение.
| Имя параметра | Описание | Допустимые значения | Значение по умолчанию | Обязательность |
|---|---|---|---|---|
start_size |
Начальный размер индекса | [1000, ∞) | 1000 | Опциональный |
radius |
Фильтрация векторов по рангам | любые float32 | Отсутствует | Опциональный |
Пример создания индекса через GO-теги
В этом примере поверх поля VecBF создаётся индекс с именем bf_idx, типом vec_bf, размерностью вектора 1024, метрикой L2 и начальным размером 1000.
// Для векторных полей тип данных должен быть слайсом (`[]float32`) или массивом(`[N]float32`).
type Item struct {
Id int `reindex:"id,,pk"`
// Для слайсов требуется явно задать тег `dimension`.
VecBF []float32 `reindex:"bf_idx,vec_bf,metric=l2,dimension=1024,start_size=1000"`
}
Пример добавления индекса в уже существующий неймспейс
При добавлении векторного индекса к существующему неймспейсу поле, поверх которого будет строиться индекс, должно быть пустым, либо содержать массив чисел длиной, равной dimension индекса.
vecOpts := reindexer.FloatVectorIndexOpts {
Metric: "l2",
Dimension: 1024,
StartSize: 20000,
Radius: 20.21,
}
indexDef := reindexer.IndexDef {
Name: "bf_idx",
JSONPaths: []string{"VecBF"},
IndexType: "vec_bf",
FieldType: "float_vector",
Config: vecOpts,
}
err := DB.AddIndex("ns_name", indexDef)
if err != nil {
panic(err)
}
curl --location --request POST http://127.0.0.1:9088/api/v1/db/vectors_db/namespaces/test_ns/indexes' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "bf_idx",
"json_paths": ["VecBF"],
"field_type": "float_vector",
"index_type": "vec_bf",
"config": {
"dimension": 1024,
"metric": "l2",
"start_size": 20000
}
}'
Параметры выборки из индекса
| Имя параметра | Описание | Допустимые значения | Значение по умолчанию | Обязательность |
|---|---|---|---|---|
k |
Максимальное количество документов, возвращаемых из индекса для последующей фильтрации | >= 1 |
Отсутствует | Обязательный при отсутствии radius |
radius |
Фильтрация векторов по рангам (rank() < radius для L2-метрики и rank() > radius для consine- и inner product-метрик) |
(0,+∞) для L2;(-∞,+∞) для inner product;(-1,1) для cosine |
Отсутствует | Обязательный при отсутствии k |
Примеры KNN-запросов к brute-force-индексу
Получение 100 ближайших соседей:
SELECT * FROM test_ns WHERE KNN(bf_idx, [2.4, 3.5, ...], k=100)
knnBaseSearchParams := reindexer.BaseKnnSearchParam{}.SetK(100)
if err != nil {
panic(err)
}
db.Query("test_ns").
WithRank().
WhereKnn("bf_idx", []float32{2.4, 3.5, ...}, knnBaseSearchParams)
curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/vectors_db/query' \
--header 'Content-Type: application/json' \
--data-raw '{
"namespace": "test_ns",
"type": "select",
"filters": [
{
"op": "and",
"cond": "knn",
"field": "bf_idx",
"value": [2.4, 3.5, ...],
"params": {"k": 100}
}
],
}'
Получение ближайших соседей в некотором радиусе:
SELECT * FROM test_ns WHERE KNN(bf_idx, [2.4, 3.5, ...], radius=10.11)
knnBaseSearchParams := reindexer.BaseKnnSearchParam{}.SetRadius(10.11)
if err != nil {
panic(err)
}
db.Query("test_ns").
WithRank().
WhereKnn("bf_idx", []float32{2.4, 3.5, ...}, knnBaseSearchParams)
curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/vectors_db/query' \
--header 'Content-Type: application/json' \
--data-raw '{
"namespace": "test_ns",
"type": "select",
"filters": [
{
"op": "and",
"cond": "knn",
"field": "bf_idx",
"value": [2.4, 3.5, ...],
"params": {"radius": 10.11}
}
],
}'
Получение 100 ближайших соседей в некотором радиусе:
SELECT * FROM test_ns WHERE KNN(bf_idx, [2.4, 3.5, ...], k=100, radius=10.11)
knnBaseSearchParams := reindexer.BaseKnnSearchParam{}.SetK(100).SetRadius(10.11)
if err != nil {
panic(err)
}
db.Query("test_ns").
WithRank().
WhereKnn("bf_idx", []float32{2.4, 3.5, ...}, knnBaseSearchParams)
curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/vectors_db/query' \
--header 'Content-Type: application/json' \
--data-raw '{
"namespace": "test_ns",
"type": "select",
"filters": [
{
"op": "and",
"cond": "knn",
"field": "bf_idx",
"value": [2.4, 3.5, ...],
"params": {"k": 100, "radius": 10.11}
}
],
}'
Получение 100 ближайших соседей и их последующая фильтрация по условию id > 5 (также явно запрошен возврат значения поля VecBF в выдаче):
SELECT *, VecBF FROM test_ns WHERE id > 5 AND KNN(bf_idx, [2.4, 3.5, ...], k=100)
knnBaseSearchParams := reindexer.BaseKnnSearchParam{}.SetK(100)
if err != nil {
panic(err)
}
db.Query("test_ns").
Select("*", "VecBF").
Where("id", reindexer.GT, 5).
WhereKnn("bf_idx", []float32{2.4, 3.5, ...}, knnBaseSearchParams)
curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/vectors_db/query' \
--header 'Content-Type: application/json' \
--data-raw '{
"namespace": "test_ns",
"type": "select",
"select_filter": ["*", "VecBF"],
"filters": [
{
"op": "and",
"cond": "gt",
"field": "id",
"value": 5
},
{
"op": "and",
"cond": "knn",
"field": "bf_idx",
"value": [2.4, 3.5, ...],
"params": {"k": 100}
}
]
}'
Получение ранга в выдаче
Пример KNN-запроса по brute-force-индексу с получением 100 ближайших соседей и соответствующих им рангов/расстояний:
SELECT *, RANK() FROM test_ns WHERE KNN(bf_idx, [2.4, 3.5, ...], k=100)
knnBaseSearchParams := reindexer.BaseKnnSearchParam{}.SetK(100)
if err != nil {
panic(err)
}
db.Query("test_ns").WithRank().WhereKnn("bf_idx", []float32{2.4, 3.5, ...}, knnBaseSearchParams)
curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/vectors_db/query' \
--header 'Content-Type: application/json' \
--data-raw '{
"namespace": "test_ns",
"type": "select",
"select_with_rank": true,
"filters": [
{
"cond": "knn",
"field": "bf_idx",
"value": [2.4, 3.5, ...],
"params": {"k": 100}
}
],
}'
Пример результирующей выдачи:
{"id": 0, "rank()": 1.245}
{"id": 7, "rank()": 4.11}
{"id": 2, "rank()": 5.0}
{"id": 10, "rank()": 12.754}