本文目录导读:

- 使用专用向量数据库(最推荐)
- PostgreSQL + pgvector 扩展(性价比最高)
- Elasticsearch + 向量插件(适合已有ES的场景)
- 纯PHP实现(仅适用于小数据量)
- 推荐选择建议
- 向量生成注意事项
在PHP项目中实现向量检索,通常有以下几种方案,按推荐程度排序:
使用专用向量数据库(最推荐)
Milvus + PHP 客户端
// 安装: composer require milvus-php/milvus-php
use Milvus\Client;
use Milvus\Collection;
$client = new Client(['host' => 'localhost', 'port' => 19530]);
// 创建集合
$collection = new Collection($client, 'documents');
$collection->create([
'fields' => [
['name' => 'id', 'type' => 'int64', 'primary_key' => true],
['name' => 'vector', 'type' => 'float_vector', 'params' => ['dim' => 768]],
['name' => 'text', 'type' => 'varchar', 'max_length' => 1000],
]
]);
// 插入向量数据
$vectors = [[0.1, 0.2, ...], [0.3, 0.4, ...]]; // 768维向量
$collection->insert([
['id' => 1, 'vector' => $vectors[0], 'text' => '文档1'],
['id' => 2, 'vector' => $vectors[1], 'text' => '文档2'],
]);
// 向量检索
$results = $collection->search([
'vector' => [0.15, 0.25, ...],
'anns_field' => 'vector',
'limit' => 10,
'metric_type' => 'COSINE'
]);
Qdrant + PHP 客户端
// 安装: composer require qdrant/php-client
use Qdrant\Client;
$client = new Client('http://localhost:6333');
// 创建集合
$client->collections()->create('documents', [
'vectors' => [
'size' => 768,
'distance' => 'Cosine'
]
]);
// 插入点
$client->points()->upsert('documents', [
'points' => [
['id' => 1, 'vector' => [0.1, 0.2, ...], 'payload' => ['text' => '文档1']],
['id' => 2, 'vector' => [0.3, 0.4, ...], 'payload' => ['text' => '文档2']],
]
]);
// 搜索
$results = $client->points()->search('documents', [
'vector' => [0.15, 0.25, ...],
'limit' => 10
]);
Weaviate + PHP
// 安装: composer require flow-php/weaviate-schema-manager
use Weaviate\Client;
$client = Client::withApiKey('your-api-key', 'https://your-instance.weaviate.io');
// 创建Schema
$client->schema()->createClass([
'class' => 'Document',
'vectorizer' => 'none', // 使用自定义向量
'properties' => [
['name' => 'text', 'dataType' => ['text']],
]
]);
// 插入数据
$client->data()->create([
'class' => 'Document',
'properties' => ['text' => '文档内容'],
'vector' => [0.1, 0.2, ...]
]);
// 向量搜索
$results = $client->graphql()->raw('
{
Get {
Document(nearVector: {vector: [0.15, 0.25, ...]}, limit: 10) {
text
_additional { distance }
}
}
}
');
PostgreSQL + pgvector 扩展(性价比最高)
// 需要PostgreSQL + pgvector扩展
// 安装: composer require doctrine/dbal
$conn = new PDO('pgsql:host=localhost;dbname=test', 'user', 'password');
// 创建表和索引(需在数据库中执行)
$conn->exec("
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
text TEXT,
vector vector(768)
);
CREATE INDEX ON documents USING ivfflat (vector vector_cosine_ops);
");
// 插入数据
$stmt = $conn->prepare("INSERT INTO documents (text, vector) VALUES (?, ?)");
$stmt->execute(['文档1', json_encode([0.1, 0.2, ...])]);
// 向量检索
$queryVector = json_encode([0.15, 0.25, ...]);
$stmt = $conn->prepare("
SELECT text, vector <=> ?::vector AS distance
FROM documents
ORDER BY vector <=> ?::vector
LIMIT 10
");
$stmt->execute([$queryVector, $queryVector]);
$results = $stmt->fetchAll();
Elasticsearch + 向量插件(适合已有ES的场景)
// 安装: composer require elasticsearch/elasticsearch
$client = Elastic\Elasticsearch\ClientBuilder::create()
->setHosts(['localhost:9200'])
->build();
// 创建索引
$client->indices()->create([
'index' => 'documents',
'body' => [
'mappings' => [
'properties' => [
'vector' => [
'type' => 'dense_vector',
'dims' => 768,
'index' => true,
'similarity' => 'cosine'
],
'text' => ['type' => 'text']
]
]
]
]);
// 插入数据
$client->index([
'index' => 'documents',
'body' => [
'text' => '文档1',
'vector' => [0.1, 0.2, ...]
]
]);
// 向量搜索
$results = $client->search([
'index' => 'documents',
'body' => [
'knn' => [
'field' => 'vector',
'query_vector' => [0.15, 0.25, ...],
'k' => 10,
'num_candidates' => 100
]
]
]);
纯PHP实现(仅适用于小数据量)
class VectorSearch {
public static function cosineSimilarity(array $vec1, array $vec2): float {
$dotProduct = 0;
$norm1 = 0;
$norm2 = 0;
for ($i = 0; $i < count($vec1); $i++) {
$dotProduct += $vec1[$i] * $vec2[$i];
$norm1 += $vec1[$i] ** 2;
$norm2 += $vec2[$i] ** 2;
}
return $dotProduct / (sqrt($norm1) * sqrt($norm2));
}
public static function search(array $vectors, array $query, int $k = 10): array {
$scores = [];
foreach ($vectors as $id => $vector) {
$scores[$id] = self::cosineSimilarity($query, $vector);
}
arsort($scores);
return array_slice($scores, 0, $k, true);
}
}
// 使用示例
$vectors = [
1 => [0.1, 0.2, 0.3],
2 => [0.4, 0.5, 0.6],
// ...
];
$query = [0.15, 0.25, 0.35];
$results = VectorSearch::search($vectors, $query, 10);
推荐选择建议
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 新项目 | pgvector | 成本低,维护简单,功能足够 |
| 大规模(>1000万) | Milvus | 性能最好,支持分布式 |
| 已有ES | ES向量搜索 | 无需新增基础设施 |
| 小数据(<10万) | 纯PHP实现 | 无额外依赖,简单快速 |
向量生成注意事项
无论使用哪种方案,都需要提前生成向量:
// 使用 OpenAI embedding
function getEmbedding(string $text): array {
$response = file_get_contents('https://api.openai.com/v1/embeddings', false,
stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\nAuthorization: Bearer YOUR_API_KEY",
'content' => json_encode(['model' => 'text-embedding-ada-002', 'input' => $text])
]
])
);
$data = json_decode($response, true);
return $data['data'][0]['embedding'];
}
推荐从 pgvector 开始,成本最低且功能完善,后续可根据需要迁移到专业的向量数据库。