本文目录导读:

在PHP项目中实现基于向量的相似度检索,主要有以下几种方法:
使用 PHP 扩展 + 外部向量数据库
Milvus + PHP SDK
// 安装:composer require milvus-io/milvus-sdk-php
use Milvus\Client;
use Milvus\Collection;
use Milvus\Index\IndexType;
// 连接 Milvus
$client = new Client('localhost', 19530);
// 插入向量数据
$collection = $client->createCollection([
'collection_name' => 'documents',
'dimension' => 128, // 向量维度
'metric_type' => MetricType::IP, // 内积相似度
]);
// 搜索相似向量
$results = $collection->search([
'vector' => [0.1, 0.2, ..., 0.8], // 查询向量
'top_k' => 10,
'metric_type' => MetricType::COSINE, // 余弦相似度
]);
Pinecone(云服务)
// 安装:composer require pinecone-io/pinecone-sdk
use Pinecone\Client;
$client = new Client([
'apiKey' => 'your-api-key',
'environment' => 'us-west1-gcp'
]);
// 插入向量
$upsertResponse = $client->index('documents')->upsert([
'vectors' => [
[
'id' => 'doc1',
'values' => [0.1, 0.2, 0.3, 0.4],
'metadata' => ['title' => '文档1']
]
]
]);
// 查询相似向量
$queryResponse = $client->index('documents')->query([
'vector' => [0.1, 0.2, 0.3, 0.4],
'topK' => 5,
'includeMetadata' => true
]);
纯 PHP 实现(小规模数据)
余弦相似度计算
class VectorSimilarity {
/**
* 计算余弦相似度
*/
public static function cosineSimilarity(array $vectorA, array $vectorB): float {
$dotProduct = 0;
$normA = 0;
$normB = 0;
for ($i = 0; $i < count($vectorA); $i++) {
$dotProduct += $vectorA[$i] * $vectorB[$i];
$normA += $vectorA[$i] * $vectorA[$i];
$normB += $vectorB[$i] * $vectorB[$i];
}
if ($normA == 0 || $normB == 0) {
return 0;
}
return $dotProduct / (sqrt($normA) * sqrt($normB));
}
/**
* 计算欧几里得距离
*/
public static function euclideanDistance(array $vectorA, array $vectorB): float {
$sum = 0;
for ($i = 0; $i < count($vectorA); $i++) {
$diff = $vectorA[$i] - $vectorB[$i];
$sum += $diff * $diff;
}
return sqrt($sum);
}
/**
* 计算点积相似度
*/
public static function dotProduct(array $vectorA, array $vectorB): float {
$dotProduct = 0;
for ($i = 0; $i < count($vectorA); $i++) {
$dotProduct += $vectorA[$i] * $vectorB[$i];
}
return $dotProduct;
}
}
// 使用示例
$vector1 = [0.1, 0.2, 0.3, 0.4];
$vector2 = [0.15, 0.25, 0.35, 0.45];
$similarity = VectorSimilarity::cosineSimilarity($vector1, $vector2);
echo "余弦相似度: " . $similarity;
向量索引实现(小规模)
class VectorIndex {
private array $vectors = [];
private array $metadata = [];
/**
* 添加向量到索引
*/
public function add(string $id, array $vector, array $meta = []): void {
$this->vectors[$id] = $vector;
$this->metadata[$id] = $meta;
}
/**
* 搜索最相似的向量
*/
public function search(array $queryVector, int $topK = 10): array {
$scores = [];
foreach ($this->vectors as $id => $vector) {
$score = VectorSimilarity::cosineSimilarity($queryVector, $vector);
$scores[$id] = $score;
}
// 排序获取 topK
arsort($scores);
$results = [];
$count = 0;
foreach ($scores as $id => $score) {
if ($count >= $topK) break;
$results[] = [
'id' => $id,
'score' => $score,
'metadata' => $this->metadata[$id] ?? []
];
$count++;
}
return $results;
}
/**
* 批量添加向量
*/
public function batchAdd(array $vectors): void {
foreach ($vectors as $item) {
$this->add($item['id'], $item['vector'], $item['metadata'] ?? []);
}
}
}
优化的大规模方案
使用 SQLite + FTS5 + 向量扩展
// 需要安装 sqlite-vector 扩展
class SQLiteVectorSearch {
private PDO $pdo;
public function __construct(string $dbPath) {
$this->pdo = new PDO("sqlite:$dbPath");
$this->initDatabase();
}
private function initDatabase(): void {
$this->pdo->exec("
CREATE VIRTUAL TABLE IF NOT EXISTS vectors USING vec0(
id INTEGER PRIMARY KEY,
embedding float[128]
)
");
}
public function insert(int $id, array $vector): void {
$stmt = $this->pdo->prepare(
"INSERT INTO vectors (id, embedding) VALUES (?, ?)"
);
$stmt->execute([$id, json_encode($vector)]);
}
public function search(array $queryVector, int $limit = 10): array {
$stmt = $this->pdo->prepare("
SELECT
id,
distance
FROM vectors
WHERE embedding MATCH ?
ORDER BY distance
LIMIT ?
");
$stmt->execute([json_encode($queryVector), $limit]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
完整的项目实现示例
class DocumentSearchEngine {
private VectorIndex $index;
private array $documents;
public function __construct() {
$this->index = new VectorIndex();
$this->documents = [];
}
/**
* 添加文档
*/
public function addDocument(string $id, string $content): void {
$vector = $this->textToVector($content);
$this->documents[$id] = $content;
$this->index->add($id, $vector, [
'content' => $content,
'length' => strlen($content)
]);
}
/**
* 将文本转换为向量(简化示例)
* 实际应用中应使用如 OpenAI Embedding API 或本地模型
*/
private function textToVector(string $text): array {
// 这是一个简化的示例,实际应该使用词嵌入模型
$words = str_word_count($text, 1);
$vector = array_fill(0, 128, 0);
foreach ($words as $word) {
$hash = crc32($word);
$index = abs($hash) % 128;
$vector[$index] += 1;
}
// 归一化
$norm = sqrt(array_sum(array_map(function($v) {
return $v * $v;
}, $vector)));
if ($norm > 0) {
$vector = array_map(function($v) use ($norm) {
return $v / $norm;
}, $vector);
}
return $vector;
}
/**
* 搜索相似文档
*/
public function search(string $query, int $limit = 5): array {
$queryVector = $this->textToVector($query);
$results = $this->index->search($queryVector, $limit);
// 格式化结果
$formatted = [];
foreach ($results as $result) {
$formatted[] = [
'id' => $result['id'],
'content' => $this->documents[$result['id']],
'score' => $result['score'],
'relevance' => round($result['score'] * 100, 2) . '%'
];
}
return $formatted;
}
}
// 使用示例
$engine = new DocumentSearchEngine();
// 添加文档
$engine->addDocument('1', 'PHP是一种流行的服务器端脚本语言');
$engine->addDocument('2', 'JavaScript用于前端网页开发');
$engine->addDocument('3', 'Python在数据科学领域广泛应用');
// 搜索
$results = $engine->search('编程语言');
foreach ($results as $result) {
echo "文档: {$result['content']}\n";
echo "相似度: {$result['relevance']}\n\n";
}
性能优化建议
class OptimizedVectorSearch {
/**
* 使用近似最近邻算法(ANN)
*/
public function approximateSearch(array $query, int $k = 10): array {
// 使用空间分割或聚类算法
// KD-Tree, R-Tree, Product Quantization
}
/**
* 分片索引
*/
public function shardSearch(array $query, int $shards = 4): array {
$results = [];
// 并行搜索多个分片
$this->parallelSearch($query, $shards, $results);
return $this->mergeResults($results);
}
/**
* 向量量化压缩
*/
private function quantizeVector(array $vector, int $bits = 8): array {
// 将浮点数向量量化为低精度整数
$quantized = [];
foreach ($vector as $value) {
$quantized[] = (int)($value * (pow(2, $bits) - 1));
}
return $quantized;
}
}
选择建议
- 数据量 < 1万:使用纯PHP实现
- 数据量 1万-100万:使用SQLite向量扩展
- 数据量 > 100万:使用Milvus、Pinecone等专业向量数据库
- 需要实时更新:选择支持动态更新的方案
- 高并发场景:使用异步架构和缓存优化
这些方法可以根据你的具体需求进行调整,需要注意,实际的文本向量化通常需要使用预训练模型(如BERT、Word2Vec等),这里为了示例使用了简化的哈希方法。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播