@mhalder/qdrant-mcp-server 1.1.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +36 -0
- package/biome.json +34 -0
- package/build/embeddings/sparse.d.ts +40 -0
- package/build/embeddings/sparse.d.ts.map +1 -0
- package/build/embeddings/sparse.js +105 -0
- package/build/embeddings/sparse.js.map +1 -0
- package/build/embeddings/sparse.test.d.ts +2 -0
- package/build/embeddings/sparse.test.d.ts.map +1 -0
- package/build/embeddings/sparse.test.js +69 -0
- package/build/embeddings/sparse.test.js.map +1 -0
- package/build/index.js +333 -32
- package/build/index.js.map +1 -1
- package/build/qdrant/client.d.ts +21 -2
- package/build/qdrant/client.d.ts.map +1 -1
- package/build/qdrant/client.js +131 -17
- package/build/qdrant/client.js.map +1 -1
- package/build/qdrant/client.test.js +429 -21
- package/build/qdrant/client.test.js.map +1 -1
- package/build/transport.test.d.ts +2 -0
- package/build/transport.test.d.ts.map +1 -0
- package/build/transport.test.js +168 -0
- package/build/transport.test.js.map +1 -0
- package/examples/README.md +16 -1
- package/examples/basic/README.md +1 -0
- package/examples/hybrid-search/README.md +236 -0
- package/package.json +3 -1
- package/src/embeddings/sparse.test.ts +87 -0
- package/src/embeddings/sparse.ts +127 -0
- package/src/index.ts +393 -59
- package/src/qdrant/client.test.ts +544 -56
- package/src/qdrant/client.ts +162 -22
- package/src/transport.test.ts +202 -0
- package/vitest.config.ts +3 -3
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BM25 Sparse Vector Generator
|
|
3
|
+
*
|
|
4
|
+
* This module provides a simple BM25-like sparse vector generation for keyword search.
|
|
5
|
+
* For production use, consider using a proper BM25 implementation or Qdrant's built-in
|
|
6
|
+
* sparse vector generation via FastEmbed.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { SparseVector } from "../qdrant/client.js";
|
|
10
|
+
|
|
11
|
+
interface TokenFrequency {
|
|
12
|
+
[token: string]: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class BM25SparseVectorGenerator {
|
|
16
|
+
private vocabulary: Map<string, number>;
|
|
17
|
+
private idfScores: Map<string, number>;
|
|
18
|
+
private documentCount: number;
|
|
19
|
+
private k1: number;
|
|
20
|
+
private b: number;
|
|
21
|
+
|
|
22
|
+
constructor(k1: number = 1.2, b: number = 0.75) {
|
|
23
|
+
this.vocabulary = new Map();
|
|
24
|
+
this.idfScores = new Map();
|
|
25
|
+
this.documentCount = 0;
|
|
26
|
+
this.k1 = k1;
|
|
27
|
+
this.b = b;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Tokenize text into words (simple whitespace tokenization + lowercase)
|
|
32
|
+
*/
|
|
33
|
+
private tokenize(text: string): string[] {
|
|
34
|
+
return text
|
|
35
|
+
.toLowerCase()
|
|
36
|
+
.replace(/[^\w\s]/g, " ")
|
|
37
|
+
.split(/\s+/)
|
|
38
|
+
.filter((token) => token.length > 0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Calculate term frequency for a document
|
|
43
|
+
*/
|
|
44
|
+
private getTermFrequency(tokens: string[]): TokenFrequency {
|
|
45
|
+
const tf: TokenFrequency = {};
|
|
46
|
+
for (const token of tokens) {
|
|
47
|
+
tf[token] = (tf[token] || 0) + 1;
|
|
48
|
+
}
|
|
49
|
+
return tf;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Build vocabulary from training documents (optional pre-training step)
|
|
54
|
+
* In a simple implementation, we can skip this and use on-the-fly vocabulary
|
|
55
|
+
*/
|
|
56
|
+
train(documents: string[]): void {
|
|
57
|
+
this.documentCount = documents.length;
|
|
58
|
+
const documentFrequency = new Map<string, number>();
|
|
59
|
+
|
|
60
|
+
// Calculate document frequency for each term
|
|
61
|
+
for (const doc of documents) {
|
|
62
|
+
const tokens = this.tokenize(doc);
|
|
63
|
+
const uniqueTokens = new Set(tokens);
|
|
64
|
+
|
|
65
|
+
for (const token of uniqueTokens) {
|
|
66
|
+
if (!this.vocabulary.has(token)) {
|
|
67
|
+
this.vocabulary.set(token, this.vocabulary.size);
|
|
68
|
+
}
|
|
69
|
+
documentFrequency.set(token, (documentFrequency.get(token) || 0) + 1);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Calculate IDF scores
|
|
74
|
+
for (const [token, df] of documentFrequency.entries()) {
|
|
75
|
+
const idf = Math.log((this.documentCount - df + 0.5) / (df + 0.5) + 1.0);
|
|
76
|
+
this.idfScores.set(token, idf);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Generate sparse vector for a query or document
|
|
82
|
+
* Returns indices and values for non-zero dimensions
|
|
83
|
+
*/
|
|
84
|
+
generate(text: string, avgDocLength: number = 50): SparseVector {
|
|
85
|
+
const tokens = this.tokenize(text);
|
|
86
|
+
const tf = this.getTermFrequency(tokens);
|
|
87
|
+
const docLength = tokens.length;
|
|
88
|
+
|
|
89
|
+
const indices: number[] = [];
|
|
90
|
+
const values: number[] = [];
|
|
91
|
+
|
|
92
|
+
// Calculate BM25 score for each term
|
|
93
|
+
for (const [token, freq] of Object.entries(tf)) {
|
|
94
|
+
// Ensure token is in vocabulary
|
|
95
|
+
if (!this.vocabulary.has(token)) {
|
|
96
|
+
// For unseen tokens, add them to vocabulary dynamically
|
|
97
|
+
this.vocabulary.set(token, this.vocabulary.size);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const index = this.vocabulary.get(token)!;
|
|
101
|
+
|
|
102
|
+
// Use a default IDF if not trained
|
|
103
|
+
const idf = this.idfScores.get(token) || 1.0;
|
|
104
|
+
|
|
105
|
+
// BM25 formula
|
|
106
|
+
const numerator = freq * (this.k1 + 1);
|
|
107
|
+
const denominator = freq + this.k1 * (1 - this.b + this.b * (docLength / avgDocLength));
|
|
108
|
+
const score = idf * (numerator / denominator);
|
|
109
|
+
|
|
110
|
+
if (score > 0) {
|
|
111
|
+
indices.push(index);
|
|
112
|
+
values.push(score);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return { indices, values };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Simple static method for generating sparse vectors without training
|
|
121
|
+
* Useful for quick implementation
|
|
122
|
+
*/
|
|
123
|
+
static generateSimple(text: string): SparseVector {
|
|
124
|
+
const generator = new BM25SparseVectorGenerator();
|
|
125
|
+
return generator.generate(text);
|
|
126
|
+
}
|
|
127
|
+
}
|