Быстрый старт#

В данном примере будет использован клиент Python для создания коллекции, загрузки данных в нее и выполнения базового поискового запроса.

Шаг 1. Скачайте и запустите#

  1. Скачайте дистрибутив Vector DB.

  2. Распакуйте архив:

    tar -xzf Vector-DB-XYZ.tar.gz
    
  3. Запустите сервер Vector DB:

    • Перейдите в директорию с бинарным файлом:

    cd Vector-DB-XYZ
    
    • Запустите сервер:

    ./qdrant
    

Теперь к Vector DB можно получить доступ по следующим адресам:

  • REST API: localhost:6333.

  • GRPC API: localhost:6334.

Шаг 2. Инициализируйте клиент#

from qdrant_client import QdrantClient

client = QdrantClient(url="http://localhost:6333")
import { QdrantClient } from "@qdrant/js-client-rest";

const client = new QdrantClient({ host: "localhost", port: 6333 });
use qdrant_client::Qdrant;

// The Rust client uses Qdrant gRPC interface
let client = Qdrant::from_url("http://localhost:6334").build()?;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;

// The Java client uses Qdrant gRPC interface
QdrantClient client = new QdrantClient(
    QdrantGrpcClient.newBuilder("localhost", 6334, false).build());
using Qdrant.Client;

// The C# client uses Qdrant gRPC interface
var client = new QdrantClient("localhost", 6334);
import "github.com/qdrant/go-client/qdrant"

// The Go client uses Qdrant gRPC interface
client, err := qdrant.NewClient(&qdrant.Config{
  Host: "localhost",
  Port: 6334,
})

По умолчанию Vector DB запускается без шифрования и аутентификации. Это означает, что любой пользователь с сетевым доступом может получить доступ Vector DB.

Шаг 3. Создайте коллекцию#

Все векторные данные будут храниться в коллекции Vector DB, например, test_collection. Эта коллекция будет использовать метрику расстояния скалярного произведения для сравнения векторов.

from qdrant_client.models import Distance, VectorParams

client.create_collection(
    collection_name="test_collection",
    vectors_config=VectorParams(size=4, distance=Distance.DOT),
)
await client.createCollection("test_collection", {
  vectors: { size: 4, distance: "Dot" },
});
use qdrant_client::qdrant::{CreateCollectionBuilder, VectorParamsBuilder};

client
    .create_collection(
        CreateCollectionBuilder::new("test_collection")
            .vectors_config(VectorParamsBuilder::new(4, Distance::Dot)),
    )
    .await?;
import io.qdrant.client.grpc.Collections.Distance;
import io.qdrant.client.grpc.Collections.VectorParams;

client.createCollectionAsync("test_collection",
        VectorParams.newBuilder().setDistance(Distance.Dot).setSize(4).build()).get();
using Qdrant.Client.Grpc;

await client.CreateCollectionAsync(collectionName: "test_collection", vectorsConfig: new VectorParams
{
    Size = 4, Distance = Distance.Dot
});
import (
  "context"

  "github.com/qdrant/go-client/qdrant"
)

client.CreateCollection(context.Background(), &qdrant.CreateCollection{
  CollectionName: "{collection_name}",
  VectorsConfig: qdrant.NewVectorsConfig(&qdrant.VectorParams{
      Size:     4,
      Distance: qdrant.Distance_Cosine,
  }),
})

Шаг 4. Добавьте векторы#

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

from qdrant_client.models import PointStruct

operation_info = client.upsert(
    collection_name="test_collection",
    wait=True,
    points=[
        PointStruct(id=1, vector=[0.05, 0.61, 0.76, 0.74], payload={"city": "Berlin"}),
        PointStruct(id=2, vector=[0.19, 0.81, 0.75, 0.11], payload={"city": "London"}),
        PointStruct(id=3, vector=[0.36, 0.55, 0.47, 0.94], payload={"city": "Moscow"}),
        PointStruct(id=4, vector=[0.18, 0.01, 0.85, 0.80], payload={"city": "New York"}),
        PointStruct(id=5, vector=[0.24, 0.18, 0.22, 0.44], payload={"city": "Beijing"}),
        PointStruct(id=6, vector=[0.35, 0.08, 0.11, 0.44], payload={"city": "Mumbai"}),
    ],
)

print(operation_info)
const operationInfo = await client.upsert("test_collection", {
  wait: true,
  points: [
    { id: 1, vector: [0.05, 0.61, 0.76, 0.74], payload: { city: "Berlin" } },
    { id: 2, vector: [0.19, 0.81, 0.75, 0.11], payload: { city: "London" } },
    { id: 3, vector: [0.36, 0.55, 0.47, 0.94], payload: { city: "Moscow" } },
    { id: 4, vector: [0.18, 0.01, 0.85, 0.80], payload: { city: "New York" } },
    { id: 5, vector: [0.24, 0.18, 0.22, 0.44], payload: { city: "Beijing" } },
    { id: 6, vector: [0.35, 0.08, 0.11, 0.44], payload: { city: "Mumbai" } },
  ],
});

console.debug(operationInfo);
use qdrant_client::qdrant::{PointStruct, UpsertPointsBuilder};

let points = vec![
    PointStruct::new(1, vec![0.05, 0.61, 0.76, 0.74], [("city", "Berlin".into())]),
    PointStruct::new(2, vec![0.19, 0.81, 0.75, 0.11], [("city", "London".into())]),
    PointStruct::new(3, vec![0.36, 0.55, 0.47, 0.94], [("city", "Moscow".into())]),
    // ..truncated
];

let response = client
    .upsert_points(UpsertPointsBuilder::new("test_collection", points).wait(true))
    .await?;

dbg!(response);
import java.util.List;
import java.util.Map;

import static io.qdrant.client.PointIdFactory.id;
import static io.qdrant.client.ValueFactory.value;
import static io.qdrant.client.VectorsFactory.vectors;

import io.qdrant.client.grpc.Points.PointStruct;
import io.qdrant.client.grpc.Points.UpdateResult;

UpdateResult operationInfo =
    client
        .upsertAsync(
            "test_collection",
            List.of(
                PointStruct.newBuilder()
                    .setId(id(1))
                    .setVectors(vectors(0.05f, 0.61f, 0.76f, 0.74f))
                    .putAllPayload(Map.of("city", value("Berlin")))
                    .build(),
                PointStruct.newBuilder()
                    .setId(id(2))
                    .setVectors(vectors(0.19f, 0.81f, 0.75f, 0.11f))
                    .putAllPayload(Map.of("city", value("London")))
                    .build(),
                PointStruct.newBuilder()
                    .setId(id(3))
                    .setVectors(vectors(0.36f, 0.55f, 0.47f, 0.94f))
                    .putAllPayload(Map.of("city", value("Moscow")))
                    .build()))
                // Truncated
            .get();

System.out.println(operationInfo);
using Qdrant.Client.Grpc;

var operationInfo = await client.UpsertAsync(collectionName: "test_collection", points: new List<PointStruct>
{
    new()
    {
        Id = 1,
            Vectors = new float[]
            {
                0.05f, 0.61f, 0.76f, 0.74f
            },
            Payload = {
                ["city"] = "Berlin"
            }
    },
    new()
    {
        Id = 2,
            Vectors = new float[]
            {
                0.19f, 0.81f, 0.75f, 0.11f
            },
            Payload = {
                ["city"] = "London"
            }
    },
    new()
    {
        Id = 3,
            Vectors = new float[]
            {
                0.36f, 0.55f, 0.47f, 0.94f
            },
            Payload = {
                ["city"] = "Moscow"
            }
    },
    // Truncated
});

Console.WriteLine(operationInfo);
import (
  "context"
  "fmt"

  "github.com/qdrant/go-client/qdrant"
)

operationInfo, err := client.Upsert(context.Background(), &qdrant.UpsertPoints{
  CollectionName: "test_collection",
  Points: []*qdrant.PointStruct{
      {
          Id:      qdrant.NewIDNum(1),
          Vectors: qdrant.NewVectors(0.05, 0.61, 0.76, 0.74),
          Payload: qdrant.NewValueMap(map[string]any{"city": "Berlin"}),
      },
      {
          Id:      qdrant.NewIDNum(2),
          Vectors: qdrant.NewVectors(0.19, 0.81, 0.75, 0.11),
          Payload: qdrant.NewValueMap(map[string]any{"city": "London"}),
      },
      {
          Id:      qdrant.NewIDNum(3),
          Vectors: qdrant.NewVectors(0.36, 0.55, 0.47, 0.94),
          Payload: qdrant.NewValueMap(map[string]any{"city": "Moscow"}),
      },
        // Truncated
  },
})
if err != nil {
  panic(err)
}
fmt.Println(operationInfo)

Ответ:

operation_id=0 status=<UpdateStatus.COMPLETED: 'completed'>
{ operation_id: 0, status: 'completed' }
PointsOperationResponse {
    result: Some(
        UpdateResult {
            operation_id: Some(
                0,
            ),
            status: Completed,
        },
    ),
    time: 0.00094027,
}
operation_id: 0
status: Completed
{ "operationId": "0", "status": "Completed" }
operation_id:0  status:Acknowledged

Шаг 5. Выполните запрос#

Создайте простой запрос для поиска наиболее близких векторов к запросу вектора [0.2, 0.1, 0.9, 0.7]:

search_result = client.query_points(
    collection_name="test_collection",
    query=[0.2, 0.1, 0.9, 0.7],
    with_payload=False,
    limit=3
).points

print(search_result)
let searchResult = await client.query(
    "test_collection", {
    query: [0.2, 0.1, 0.9, 0.7],
    limit: 3
});

console.debug(searchResult.points);
use qdrant_client::qdrant::QueryPointsBuilder;

let search_result = client
    .query(
        QueryPointsBuilder::new("test_collection")
            .query(vec![0.2, 0.1, 0.9, 0.7])
    )
    .await?;

dbg!(search_result);
import java.util.List;

import io.qdrant.client.grpc.Points.ScoredPoint;
import io.qdrant.client.grpc.Points.QueryPoints;

import static io.qdrant.client.QueryFactory.nearest;

List<ScoredPoint> searchResult =
    client.queryAsync(QueryPoints.newBuilder()
                .setCollectionName("test_collection")
                .setLimit(3)
                .setQuery(nearest(0.2f, 0.1f, 0.9f, 0.7f))
                .build()).get();
      
System.out.println(searchResult);
var searchResult = await client.QueryAsync(
    collectionName: "test_collection",
    query: new float[] { 0.2f, 0.1f, 0.9f, 0.7f },
    limit: 3,
);

Console.WriteLine(searchResult);
import (
  "context"
  "fmt"

  "github.com/qdrant/go-client/qdrant"
)

searchResult, err := client.Query(context.Background(), &qdrant.QueryPoints{
  CollectionName: "test_collection",
  Query:          qdrant.NewQuery(0.2, 0.1, 0.9, 0.7),
})
if err != nil {
  panic(err)
}

fmt.Println(searchResult)

Ответ:

[
  {
    "id": 4,
    "version": 0,
    "score": 1.362,
    "payload": null,
    "vector": null
  },
  {
    "id": 1,
    "version": 0,
    "score": 1.273,
    "payload": null,
    "vector": null
  },
  {
    "id": 3,
    "version": 0,
    "score": 1.208,
    "payload": null,
    "vector": null
  }
]

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

Шаг 6. Добавьте фильтр#

Отфильтруйте результаты по полезной нагрузке. Найдите ближайшие результаты, включающие "Лондон".

from qdrant_client.models import Filter, FieldCondition, MatchValue

search_result = client.query_points(
    collection_name="test_collection",
    query=[0.2, 0.1, 0.9, 0.7],
    query_filter=Filter(
        must=[FieldCondition(key="city", match=MatchValue(value="London"))]
    ),
    with_payload=True,
    limit=3,
).points

print(search_result)
searchResult = await client.query("test_collection", {
    query: [0.2, 0.1, 0.9, 0.7],
    filter: {
        must: [{ key: "city", match: { value: "London" } }],
    },
    with_payload: true,
    limit: 3,
});

console.debug(searchResult);
use qdrant_client::qdrant::{Condition, Filter, QueryPointsBuilder};

let search_result = client
    .query(
        QueryPointsBuilder::new("test_collection")
            .query(vec![0.2, 0.1, 0.9, 0.7])
            .filter(Filter::must([Condition::matches(
                "city",
                "London".to_string(),
            )]))
            .with_payload(true),
    )
    .await?;

dbg!(search_result);
import static io.qdrant.client.ConditionFactory.matchKeyword;

List<ScoredPoint> searchResult =
    client.queryAsync(QueryPoints.newBuilder()
                .setCollectionName("test_collection")
                .setLimit(3)
                .setFilter(Filter.newBuilder().addMust(matchKeyword("city", "London")))
                .setQuery(nearest(0.2f, 0.1f, 0.9f, 0.7f))
                .setWithPayload(enable(true))
                .build()).get();

System.out.println(searchResult);
using static Qdrant.Client.Grpc.Conditions;

var searchResult = await client.QueryAsync(
    collectionName: "test_collection",
    query: new float[] { 0.2f, 0.1f, 0.9f, 0.7f },
    filter: MatchKeyword("city", "London"),
    limit: 3,
    payloadSelector: true
);

Console.WriteLine(searchResult);
import (
  "context"
  "fmt"

  "github.com/qdrant/go-client/qdrant"
)

searchResult, err := client.Query(context.Background(), &qdrant.QueryPoints{
  CollectionName: "test_collection",
  Query:          qdrant.NewQuery(0.2, 0.1, 0.9, 0.7),
  Filter: &qdrant.Filter{
      Must: []*qdrant.Condition{
          qdrant.NewMatch("city", "London"),
      },
  },
  WithPayload: qdrant.NewWithPayload(true),
})
if err != nil {
  panic(err)
}

fmt.Println(searchResult)

Ответ:

[
    {
        "id": 2,
        "version": 0,
        "score": 0.871,
        "payload": {
            "city": "London"
        },
        "vector": null
    }
]

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

Итак, только что был выполнен векторный поиск. Были загружены векторы в базу данных и отправлен запрос в базу данных со своим собственным вектором. Vector DB нашел самые близкие результаты и представил оценку сходства.

Примечание

Существует другой способ запуска Vector DB локально. Разработчикам на Python, рекомендуется попробовать режим Local Mode в клиенте поскольку его настройка занимает всего несколько минут.