🚀 Попробуйте Zilliz Cloud, полностью управляемый Milvus, бесплатно — ощутите 10-кратное увеличение производительности! Попробовать сейчас>

milvus-logo
LFAI
Главная
  • Руководство пользователя
  • Home
  • Docs
  • Руководство пользователя

  • Схема и поля данных

  • Разреженный вектор

Разреженный вектор

Разреженные векторы - важный метод представления данных в информационном поиске и обработке естественного языка. Хотя плотные векторы популярны благодаря своим превосходным возможностям семантического понимания, разреженные векторы часто дают более точные результаты, когда речь идет о приложениях, требующих точного соответствия ключевых слов или фраз.

Обзор

Разреженный вектор - это особое представление высокоразмерных векторов, в котором большинство элементов равны нулю, и только несколько измерений имеют ненулевые значения. Эта характеристика делает разреженные векторы особенно эффективными при работе с крупномасштабными, высокоразмерными, но разреженными данными. К числу распространенных приложений относятся.

  • Анализ текста: Представление документов в виде векторов "мешок слов", где каждое измерение соответствует слову, и только слова, встречающиеся в документе, имеют ненулевые значения.

  • Рекомендательные системы: Матрицы взаимодействия пользователя и элемента, где каждое измерение представляет собой оценку пользователем определенного элемента, причем большинство пользователей взаимодействуют только с несколькими элементами.

  • Обработка изображений: Локальное представление признаков, сосредоточенное только на ключевых точках изображения, в результате чего получаются высокоразмерные разреженные векторы.

Как показано на диаграмме ниже, плотные векторы обычно представляются в виде непрерывных массивов, где каждая позиция имеет значение (например, [0.3, 0.8, 0.2, 0.3, 0.1]). В отличие от них, разреженные векторы хранят только ненулевые элементы и их индексы, часто представляемые в виде пар ключ-значение (например, [{2: 0.2}, ..., {9997: 0.5}, {9999: 0.7}]). Такое представление значительно сокращает объем памяти и повышает эффективность вычислений, особенно при работе с очень высокоразмерными данными (например, 10 000 измерений).

Spare vector representation Представление разреженных векторов

Разреженные векторы могут быть сгенерированы с помощью различных методов, таких как TF-IDF (Term Frequency-Inverse Document Frequency) и BM25 в обработке текстов. Кроме того, Milvus предлагает удобные методы, помогающие генерировать и обрабатывать разреженные векторы. Подробнее см. в разделе "Вкрапления".

Для текстовых данных Milvus также предоставляет возможности полнотекстового поиска, позволяя выполнять векторный поиск непосредственно в необработанных текстовых данных без использования внешних моделей встраивания для генерации разреженных векторов. Дополнительную информацию см. в разделе Полнотекстовый поиск.

После векторизации данные можно хранить в Milvus для управления и поиска векторов. На схеме ниже показан основной процесс.

Use sparse vector in Milvus Использование разреженного вектора в Milvus

Помимо разреженных векторов, Milvus также поддерживает плотные векторы и двоичные векторы. Плотные векторы идеально подходят для фиксации глубоких семантических связей, а двоичные векторы - для таких сценариев, как быстрое сравнение сходства и дедупликация контента. Дополнительные сведения см. в разделах "Плотный вектор" и "Двоичный вектор".

Использование разреженных векторов в Milvus

Milvus поддерживает представление разреженных векторов в любом из следующих форматов.

  • Разреженная матрица (с использованием класса scipy.sparse ).

    from scipy.sparse import csr_matrix
    
    # Create a sparse matrix
    row = [0, 0, 1, 2, 2, 2]
    col = [0, 2, 2, 0, 1, 2]
    data = [1, 2, 3, 4, 5, 6]
    sparse_matrix = csr_matrix((data, (row, col)), shape=(3, 3))
    
    # Represent sparse vector using the sparse matrix
    sparse_vector = sparse_matrix.getrow(0)
    
    
  • Список словарей (в формате {dimension_index: value, ...})

    # Represent sparse vector using a dictionary
    sparse_vector = [{1: 0.5, 100: 0.3, 500: 0.8, 1024: 0.2, 5000: 0.6}]
    
    
    SortedMap<Long, Float> sparseVector = new TreeMap<>();
    sparseVector.put(1L, 0.5f);
    sparseVector.put(100L, 0.3f);
    sparseVector.put(500L, 0.8f);
    sparseVector.put(1024L, 0.2f);
    sparseVector.put(5000L, 0.6f);
    
    
  • Список итераторов кортежей (в формате [(dimension_index, value)])

    # Represent sparse vector using a list of tuples
    sparse_vector = [[(1, 0.5), (100, 0.3), (500, 0.8), (1024, 0.2), (5000, 0.6)]]
    
    

Добавьте векторное поле

Чтобы использовать разреженные векторы в Milvus, при создании коллекции определите поле для хранения разреженных векторов. Этот процесс включает в себя.

  1. Установка datatype в поддерживаемый тип данных разреженного вектора, SPARSE_FLOAT_VECTOR.

  2. Размерность указывать не нужно.

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530")

client.drop_collection(collection_name="my_sparse_collection")

schema = client.create_schema(
    auto_id=True,
    enable_dynamic_fields=True,
)

schema.add_field(field_name="pk", datatype=DataType.VARCHAR, is_primary=True, max_length=100)
schema.add_field(field_name="sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR)

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;

import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;

MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
        .uri("http://localhost:19530")
        .build());
        
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.setEnableDynamicField(true);
schema.addField(AddFieldReq.builder()
        .fieldName("pk")
        .dataType(DataType.VarChar)
        .isPrimaryKey(true)
        .autoID(true)
        .maxLength(100)
        .build());

schema.addField(AddFieldReq.builder()
        .fieldName("sparse_vector")
        .dataType(DataType.SparseFloatVector)
        .build());

import { DataType } from "@zilliz/milvus2-sdk-node";

const schema = [
  {
    name: "metadata",
    data_type: DataType.JSON,
  },
  {
    name: "pk",
    data_type: DataType.Int64,
    is_primary_key: true,
  },
  {
    name: "sparse_vector",
    data_type: DataType.SparseFloatVector,
  }
];


export primaryField='{
    "fieldName": "pk",
    "dataType": "VarChar",
    "isPrimary": true,
    "elementTypeParams": {
        "max_length": 100
    }
}'

export vectorField='{
    "fieldName": "sparse_vector",
    "dataType": "SparseFloatVector"
}'

export schema="{
    \"autoID\": true,
    \"fields\": [
        $primaryField,
        $vectorField
    ]
}"

В этом примере для хранения разреженных векторов добавлено векторное поле с именем sparse_vector. Тип данных этого поля - SPARSE_FLOAT_VECTOR.

Установка параметров индекса для векторного поля

Процесс создания индекса для разреженных векторов аналогичен процессу создания индекса для плотных векторов, но с отличиями в заданном типе индекса (index_type), метрике расстояния (metric_type) и параметрах индекса (params).

index_params = client.prepare_index_params()

index_params.add_index(
    field_name="sparse_vector",
    index_name="sparse_inverted_index",
    index_type="SPARSE_INVERTED_INDEX",
    metric_type="IP",
    params={"inverted_index_algo": "DAAT_MAXSCORE"},
)

import io.milvus.v2.common.IndexParam;
import java.util.*;

List<IndexParam> indexes = new ArrayList<>();
Map<String,Object> extraParams = new HashMap<>();
extraParams.put("inverted_index_algo": "DAAT_MAXSCORE");
indexes.add(IndexParam.builder()
        .fieldName("sparse_vector")
        .indexName("sparse_inverted_index")
        .indexType(IndexParam.IndexType.SPARSE_INVERTED_INDEX)
        .metricType(IndexParam.MetricType.IP)
        .extraParams(extraParams)
        .build());

const indexParams = await client.createIndex({
    index_name: 'sparse_inverted_index',
    field_name: 'sparse_vector',
    metric_type: MetricType.IP,
    index_type: IndexType.SPARSE_INVERTED_INDEX,
    params: {
      inverted_index_algo: 'DAAT_MAXSCORE',
    },
});

export indexParams='[
        {
            "fieldName": "sparse_vector",
            "metricType": "IP",
            "indexName": "sparse_inverted_index",
            "indexType": "SPARSE_INVERTED_INDEX",
            "params":{"inverted_index_algo": "DAAT_MAXSCORE"}
        }
    ]'

В примере выше:

  • index_type: Тип индекса для создания разреженного векторного поля. Допустимые значения:

    • SPARSE_INVERTED_INDEX: Инвертированный индекс общего назначения для разреженных векторов.

    Начиная с Milvus 2.5.4 и далее, SPARSE_WAND устаревает. Вместо него рекомендуется использовать "inverted_index_algo": "DAAT_WAND" для эквивалентности и сохранения совместимости.

  • metric_type: Метрика, используемая для вычисления сходства между разреженными векторами. Допустимые значения:

    • IP (Внутреннее произведение): Измеряет сходство с помощью точечного произведения.

    • BM25: Обычно используется для полнотекстового поиска, фокусируясь на текстовом сходстве.

      Более подробную информацию см. в разделе Типы метрик и полнотекстовый поиск.

  • params.inverted_index_algo: Алгоритм, используемый для построения и запроса индекса. Допустимые значения:

    • "DAAT_MAXSCORE" (по умолчанию): Оптимизированная обработка запросов Document-at-a-Time (DAAT) с использованием алгоритма MaxScore. MaxScore обеспечивает лучшую производительность при больших значениях k или запросах с большим количеством терминов, пропуская термины и документы, которые, вероятно, будут иметь минимальное влияние. Это достигается путем разделения терминов на существенные и несущественные группы на основе их максимальных баллов влияния, фокусируясь на терминах, которые могут внести вклад в результаты top-k.

    • "DAAT_WAND": Оптимизированная обработка запросов DAAT с помощью алгоритма WAND. WAND оценивает меньшее количество документов, попавших в запрос, используя максимальные оценки влияния для пропуска неконкурентных документов, но при этом имеет более высокие накладные расходы в расчете на одно попадание. Это делает WAND более эффективным для запросов с небольшими значениями k или коротких запросов, где пропуск документов более целесообразен.

    • "TAAT_NAIVE": Обработка запросов с использованием базового термина (TAAT). Хотя он медленнее, чем DAAT_MAXSCORE и DAAT_WAND, TAAT_NAIVE обладает уникальным преимуществом. В отличие от алгоритмов DAAT, использующих кэшированные оценки максимального влияния, которые остаются статичными независимо от изменений глобального параметра коллекции (avgdl), TAAT_NAIVE динамически адаптируется к таким изменениям.

Создание коллекции

После того как настройки разреженного вектора и индекса завершены, можно создать коллекцию, содержащую разреженные векторы. В примере ниже используется метод create_collection для создания коллекции с именем my_sparse_collection.

client.create_collection(
    collection_name="my_sparse_collection",
    schema=schema,
    index_params=index_params
)

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;

MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
        .uri("http://localhost:19530")
        .build());
        
CreateCollectionReq requestCreate = CreateCollectionReq.builder()
        .collectionName("my_sparse_collection")
        .collectionSchema(schema)
        .indexParams(indexes)
        .build();
client.createCollection(requestCreate);

import { MilvusClient } from "@zilliz/milvus2-sdk-node";

const client = new MilvusClient({
    address: 'http://localhost:19530'
});

await client.createCollection({
    collection_name: 'my_sparse_collection',
    schema: schema,
    index_params: indexParams
});

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{
    \"collectionName\": \"my_sparse_collection\",
    \"schema\": $schema,
    \"indexParams\": $indexParams
}"

Вставка данных

После создания коллекции вставьте данные, содержащие разреженные векторы.

sparse_vectors = [
    {"sparse_vector": {1: 0.5, 100: 0.3, 500: 0.8}},
    {"sparse_vector": {10: 0.1, 200: 0.7, 1000: 0.9}},
]

client.insert(
    collection_name="my_sparse_collection",
    data=sparse_vectors
)

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.milvus.v2.service.vector.request.InsertReq;
import io.milvus.v2.service.vector.response.InsertResp;

List<JsonObject> rows = new ArrayList<>();
Gson gson = new Gson();
{
    JsonObject row = new JsonObject();
    SortedMap<Long, Float> sparse = new TreeMap<>();
    sparse.put(1L, 0.5f);
    sparse.put(100L, 0.3f);
    sparse.put(500L, 0.8f);
    row.add("sparse_vector", gson.toJsonTree(sparse));
    rows.add(row);
}
{
    JsonObject row = new JsonObject();
    SortedMap<Long, Float> sparse = new TreeMap<>();
    sparse.put(10L, 0.1f);
    sparse.put(200L, 0.7f);
    sparse.put(1000L, 0.9f);
    row.add("sparse_vector", gson.toJsonTree(sparse));
    rows.add(row);
}

InsertResp insertR = client.insert(InsertReq.builder()
        .collectionName("my_sparse_collection")
        .data(rows)
        .build());

const data = [
  { sparse_vector: { "1": 0.5, "100": 0.3, "500": 0.8 } },
  { sparse_vector: { "10": 0.1, "200": 0.7, "1000": 0.9 } },
];
client.insert({
  collection_name: "my_sparse_collection",
  data: data,
});


curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "data": [
        {"sparse_vector": {"1": 0.5, "100": 0.3, "500": 0.8}},
        {"sparse_vector": {"10": 0.1, "200": 0.7, "1000": 0.9}}        
    ],
    "collectionName": "my_sparse_collection"
}'

## {"code":0,"cost":0,"data":{"insertCount":2,"insertIds":["453577185629572534","453577185629572535"]}}

Чтобы выполнить поиск по сходству с использованием разреженных векторов, подготовьте вектор запроса и параметры поиска.

# Prepare search parameters
search_params = {
    "params": {"drop_ratio_search": 0.2},  # Additional optional search parameters
}

# Prepare the query vector
query_vector = [{1: 0.2, 50: 0.4, 1000: 0.7}]

В этом примере drop_ratio_search - необязательный параметр специально для разреженных векторов, позволяющий тонко настраивать малые значения в векторе запроса во время поиска. Например, при использовании {"drop_ratio_search": 0.2} наименьшие 20 % значений в векторе запроса будут игнорироваться во время поиска.

Затем выполните поиск сходства, используя метод search.

res = client.search(
    collection_name="my_sparse_collection",
    data=query_vector,
    limit=3,
    output_fields=["pk"],
    search_params=search_params,
)

print(res)

# Output
# data: ["[{'id': '453718927992172266', 'distance': 0.6299999952316284, 'entity': {'pk': '453718927992172266'}}, {'id': '453718927992172265', 'distance': 0.10000000149011612, 'entity': {'pk': '453718927992172265'}}]"]

import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.SparseFloatVec;
import io.milvus.v2.service.vector.response.SearchResp;

Map<String,Object> searchParams = new HashMap<>();
searchParams.put("drop_ratio_search", 0.2);

SortedMap<Long, Float> sparse = new TreeMap<>();
sparse.put(10L, 0.1f);
sparse.put(200L, 0.7f);
sparse.put(1000L, 0.9f);

SparseFloatVec queryVector = new SparseFloatVec(sparse);

SearchResp searchR = client.search(SearchReq.builder()
        .collectionName("my_sparse_collection")
        .data(Collections.singletonList(queryVector))
        .annsField("sparse_vector")
        .searchParams(searchParams)
        .topK(3)
        .outputFields(Collections.singletonList("pk"))
        .build());
        
System.out.println(searchR.getSearchResults());

// Output
//
// [[SearchResp.SearchResult(entity={pk=453444327741536759}, score=1.31, id=453444327741536759), SearchResp.SearchResult(entity={pk=453444327741536756}, score=1.31, id=453444327741536756), SearchResp.SearchResult(entity={pk=453444327741536753}, score=1.31, id=453444327741536753)]]

client.search({
    collection_name: 'my_sparse_collection',
    data: {1: 0.2, 50: 0.4, 1000: 0.7},
    limit: 3,
    output_fields: ['pk'],
    params: {
        drop_ratio_search: 0.2
    }
});

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "collectionName": "my_sparse_collection",
    "data": [
        {"1": 0.2, "50": 0.4, "1000": 0.7}
    ],
    "annsField": "sparse_vector",
    "limit": 3,
    "searchParams":{
        "params":{"drop_ratio_search": 0.2}
    },
    "outputFields": ["pk"]
}'

## {"code":0,"cost":0,"data":[{"distance":0.63,"id":"453577185629572535","pk":"453577185629572535"},{"distance":0.1,"id":"453577185629572534","pk":"453577185629572534"}]}

Дополнительные сведения о параметрах поиска по сходству см. в разделе Базовый поиск ANN.

Ограничения

При использовании разреженных векторов в Milvus учитывайте следующие ограничения:

  • В настоящее время для разреженных векторов поддерживаются только метрики расстояния IP и BM25 (для полнотекстового поиска). Высокая размерность разреженных векторов делает L2 и косинусное расстояние нецелесообразными.

  • Для полей разреженных векторов поддерживается только тип индекса SPARSE_INVERTED_INDEX.

  • Типы данных, поддерживаемые для разреженных векторов:

    • Размерная часть должна быть беззнаковым 32-битным целым числом;
    • Часть значения может быть неотрицательным 32-битным числом с плавающей точкой.
  • Разреженные векторы должны удовлетворять следующим требованиям для вставки и поиска:

    • Хотя бы одно значение в векторе ненулевое;
    • Индексы вектора неотрицательны.

ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ

  • Может ли размерность разреженного вложения быть любой дискретной величиной в пространстве uint32?

    Да, за одним исключением. Размерность разреженного вложения может быть любой величиной в диапазоне [0, maximum of uint32). Это означает, что вы не можете использовать максимальное значение uint32.

  • Поиск в растущих сегментах осуществляется через индекс или методом грубой силы?

    Поиск по растущим сегментам осуществляется через индекс того же типа, что и индекс запечатанного сегмента. Для новых растущих сегментов до построения индекса используется поиск методом грубой силы.

  • Можно ли в одной коллекции иметь как разреженные, так и плотные векторы?

    Да, благодаря поддержке нескольких типов векторов можно создавать коллекции, содержащие как разреженные, так и плотные векторные столбцы, и выполнять в них гибридный поиск.

Попробуйте Managed Milvus бесплатно

Zilliz Cloud работает без проблем, поддерживается Milvus и в 10 раз быстрее.

Начать
Обратная связь

Была ли эта страница полезной?