This library is a PHP Client for Qdrant.
Qdrant is a vector similarity engine & vector database. It deploys as an API service providing search for the nearest high-dimensional vectors. With Qdrant, embeddings or neural network encoders can be turned into full-fledged applications for matching, searching, recommending, and much more!
You can install the client in your PHP project using composer:
composer require hkulekci/qdrantStarting with v1.19.0, the version of this client follows the Qdrant server version: 1.19.x releases target and
are tested against Qdrant 1.19, and new client releases are published together with new Qdrant minor versions.
Patch releases (1.19.1, 1.19.2, ...) contain client-side fixes only.
Important
The jump from v1.0.0 to v1.19.0 only aligns the version numbers with Qdrant, it does not remove or rename any
public API. Still, please review the following before upgrading:
- Features such as TurboQuant, memory tiers, named vector management or quotas require a Qdrant server that supports them. Older servers may reject or silently ignore the new fields.
falseand0values set onHnswConfig,WalConfigandCollectionParams(for exampleon_disk: false) were previously dropped and are now sent to the server.CreateShardKeynow sendsshards_number; the shard number was previously ignored by the server.on_disk,always_ram,on_disk_payload,memmap_thresholdandinit_fromare deprecated in Qdrant and marked@deprecatedin the client. Prefer thememoryoptions and snapshots.- The legacy
search()andrecommend()endpoints are deprecated; use the Query API.
include __DIR__ . "/../vendor/autoload.php";
include_once 'config.php';
use Qdrant\Qdrant;
use Qdrant\Config;
use Qdrant\Http\Builder;
$config = new Config(QDRANT_HOST);
$config->setApiKey(QDRANT_API_KEY);
$transport = (new Builder())->build($config);
$client = new Qdrant($transport);use Qdrant\Endpoints\Collections;
use Qdrant\Models\Request\CreateCollection;
use Qdrant\Models\Request\VectorParams;
$createCollection = new CreateCollection();
$createCollection->addVector(new VectorParams(1536, VectorParams::DISTANCE_COSINE), 'content');
$response = $client->collections('contents')->create($createCollection);use Qdrant\Models\PointsStruct;
use Qdrant\Models\PointStruct;
use Qdrant\Models\VectorStruct;
$openai = OpenAI::client(OPENAI_API_KEY);
$query = 'sustainable agricultural startups';
$response = $openai->embeddings()->create([
'model' => 'text-embedding-ada-002',
'input' => $query,
]);
$embedding = array_values($response->embeddings[0]->embedding);
$points = new PointsStruct();
$points->addPoint(
new PointStruct(
(int) $imageId,
new VectorStruct($embedding, 'content'),
[
'id' => 1,
'meta' => 'Meta data'
]
)
);
$client->collections('contents')->points()->upsert($points);While upsert data, if you want to wait for upsert to actually happen, you can use query parameters:
$client->collections('contents')->points()->upsert($points, ['wait' => 'true']);You can check for more parameters : https://qdrant.github.io/qdrant/redoc/index.html#tag/points/operation/upsert_points
Use the universal Query API (points()->query()). The legacy search() and recommend() endpoints are
deprecated and have been removed from the Qdrant OpenAPI specification since Qdrant 1.19.
use Qdrant\Models\Filter\Condition\MatchString;
use Qdrant\Models\Filter\Filter;
use Qdrant\Models\Request\Points\QueryRequest;
$request = (new QueryRequest())
->setQuery(['nearest' => $embedding])
->setUsing('content')
->setFilter((new Filter())->addMust(new MatchString('name', 'Palm')))
->setLimit(10)
->setParams(['hnsw_ef' => 128, 'exact' => false])
->setWithPayload(true);
$response = $client->collections('contents')->points()->query()->query($request);
foreach ($response['result']['points'] as $item) {
echo $item['score'] . ';' . $item['payload']['id'] . PHP_EOL;
}Hybrid search with prefetch and fusion (weighted RRF, MMR, formula and relevance feedback queries are passed the same way):
$request = (new QueryRequest())
->setPrefetch([
['query' => $denseEmbedding, 'using' => 'dense', 'limit' => 50],
['query' => ['indices' => [1, 42], 'values' => [0.3, 0.7]], 'using' => 'keywords', 'limit' => 50],
])
->setQuery(['rrf' => ['k' => 60, 'weights' => [1.0, 0.5]]])
->setLimit(10);TurboQuant (Qdrant 1.18+) gives up to 8x vector compression with high recall:
use Qdrant\Models\Request\CollectionConfig\Memory;
use Qdrant\Models\Request\CollectionConfig\TurboQuantization;
$createCollection = (new CreateCollection())
->addVector(new VectorParams(1536, VectorParams::DISTANCE_COSINE), 'content')
->setQuantizationConfig(new TurboQuantization(TurboQuantization::BITS_4, Memory::PINNED));Since Qdrant 1.19 vectors can be stored only as TurboQuant 4-bit, without keeping the original vectors:
$createCollection->addVector(
(new VectorParams(1536, VectorParams::DISTANCE_COSINE))->setDatatype(VectorParams::DATATYPE_TURBO4),
'content'
);Other quantization methods are available as ScalarQuantization, ProductQuantization and BinaryQuantization
(with encoding / query_encoding for 1.5-bit, 2-bit and asymmetric binary quantization). Use
DisabledQuantization with UpdateCollection to turn quantization off.
Since Qdrant 1.19 the memory option (cold, cached, pinned) replaces the on_disk and always_ram flags
for each collection component:
use Qdrant\Models\Request\CollectionConfig\HnswConfig;
$createCollection = (new CreateCollection())
->addVector((new VectorParams(1536, VectorParams::DISTANCE_COSINE))->setMemory(Memory::COLD), 'content')
->setHnswConfig((new HnswConfig())->setMemory(Memory::CACHED))
->setQuantizationConfig(new TurboQuantization(memory: Memory::PINNED))
->setPayloadMemory(Memory::COLD);use Qdrant\Models\Request\CreateVector;
use Qdrant\Models\Request\SparseVectorParams;
$createCollection->addSparseVector('keywords', (new SparseVectorParams())->setModifier(SparseVectorParams::MODIFIER_IDF));
// Add or remove named vectors on an existing collection (Qdrant 1.18+)
$client->collections('contents')->vectors()->create('summary', CreateVector::dense(384, VectorParams::DISTANCE_COSINE));
$client->collections('contents')->vectors()->create('bm25', CreateVector::sparse(SparseVectorParams::MODIFIER_IDF));
$client->collections('contents')->vectors()->delete('summary');use Qdrant\Models\Filter\Condition\MatchInt;
use Qdrant\Models\Request\UpdateMode;
// Only insert points that do not exist yet (Qdrant 1.17+)
$client->collections('contents')->points()->upsert($points, ['wait' => 'true'], UpdateMode::INSERT_ONLY);
// Only update existing points that match the filter (Qdrant 1.16+)
$client->collections('contents')->points()->upsert(
$points,
updateFilter: (new Filter())->addMust(new MatchInt('version', 1))
);Besides the classic conditions (MatchString, MatchInt, MatchAny, Range, GeoRadius, ...) the client supports
MatchPrefix (1.19, requires a keyword index created with prefix: true), MatchTextAny, MatchPhrase, IsNull,
HasVector and Slice (1.19, deterministic partitioning for parallel scroll or sampling):
use Qdrant\Models\Filter\Condition\MatchPrefix;
use Qdrant\Models\Filter\Condition\Slice;
use Qdrant\Models\Request\CreateIndex;
$client->collections('contents')->index()->create(new CreateIndex('category', ['type' => 'keyword', 'prefix' => true]));
$filter = (new Filter())
->addMust(new MatchPrefix('category', 'elec'))
->addMust(new Slice(0, 4)); // first of 4 slicesuse Qdrant\Models\Request\QuotaConfig;
$client->collections('contents')->optimizations(['with' => 'queued,completed']); // optimization progress (1.17+)
$client->collections('contents')->shards()->list(); // shard keys (1.17+)
$client->cluster()->telemetry(); // cluster-wide telemetry (1.17+)
// Global resource quotas (1.19+)
$client->quotas()->get();
$client->quotas()->update((new QuotaConfig())->setMaxDiskUsagePercent(90));This library ships with an AI context file that helps AI assistants (Claude Code, etc.) understand the full API surface. To enable it in your project:
mkdir -p .claude/docs
cp vendor/hkulekci/qdrant/docs/ai-context.md .claude/docs/qdrant-php.mdThis gives AI tools a complete reference of all endpoints, request models, filters, and usage examples.