@memberjunction/ai-vectors-sqlserver 0.0.1 → 5.39.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/README.md +86 -43
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/models/SQLServerVectorDatabase.d.ts +109 -0
- package/dist/models/SQLServerVectorDatabase.d.ts.map +1 -0
- package/dist/models/SQLServerVectorDatabase.js +704 -0
- package/dist/models/SQLServerVectorDatabase.js.map +1 -0
- package/dist/models/sqlserverColocatedSQL.d.ts +95 -0
- package/dist/models/sqlserverColocatedSQL.d.ts.map +1 -0
- package/dist/models/sqlserverColocatedSQL.js +255 -0
- package/dist/models/sqlserverColocatedSQL.js.map +1 -0
- package/package.json +30 -7
package/README.md
CHANGED
|
@@ -1,45 +1,88 @@
|
|
|
1
1
|
# @memberjunction/ai-vectors-sqlserver
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
##
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
3
|
+
A **colocated** MemberJunction vector-database provider backed by **SQL Server 2025 native vectors**
|
|
4
|
+
(the `VECTOR(N)` type and the `VECTOR_SEARCH` DiskANN table-valued function). It stores and queries
|
|
5
|
+
embeddings inside the application's own SQL Server database — borrowing the active data provider's
|
|
6
|
+
connection rather than opening a separate pool — so vectors live alongside the entity rows they
|
|
7
|
+
describe and can be searched with the database's native ANN index.
|
|
8
|
+
|
|
9
|
+
Registered with the MJ class factory as **`SQLServerVectorDatabase`** (`@RegisterClass(VectorDBBase, 'SQLServerVectorDatabase')`).
|
|
10
|
+
|
|
11
|
+
> **Status:** validated end-to-end against a live **SQL Server 2025 RTM** container (17.0.4050)
|
|
12
|
+
> in `sibling` storage mode — index create, upsert, exact query, metadata (`JSON_VALUE`) filtering,
|
|
13
|
+
> and result mapping all confirmed working. The `entityColumn` mode and the approximate
|
|
14
|
+
> (`VECTOR_SEARCH`) path on Azure SQL Database remain unexercised; treat those as untested.
|
|
15
|
+
|
|
16
|
+
## How it works
|
|
17
|
+
|
|
18
|
+
This is a [colocated](../../Database/README.md) provider: it implements no connection logic of its
|
|
19
|
+
own. Instead it receives the active relational connection through MemberJunction's
|
|
20
|
+
`IColocatedVectorHost` adapter (implemented by `SQLServerDataProvider`) and runs all DDL/DML through
|
|
21
|
+
it. When a transaction is open on that connection, vector writes participate in it.
|
|
22
|
+
|
|
23
|
+
### Query path
|
|
24
|
+
|
|
25
|
+
The provider prefers the DiskANN-aware **`VECTOR_SEARCH`** TVF (`SELECT TOP (N) WITH APPROXIMATE`),
|
|
26
|
+
which engages the vector index and is dramatically faster than a brute-force scan at scale. But that
|
|
27
|
+
surface is **not present in every SQL Server 2025 build** — verified live, **boxed SQL Server 2025 RTM
|
|
28
|
+
(17.0.4050) does not have `VECTOR_SEARCH`/`WITH APPROXIMATE` or `CREATE VECTOR INDEX … DiskANN`**; only
|
|
29
|
+
the `VECTOR(n)` type and the exact `VECTOR_DISTANCE` function ship there. (The approximate surface is
|
|
30
|
+
currently Azure SQL Database, and likely a later boxed CU.)
|
|
31
|
+
|
|
32
|
+
So the provider **detects support lazily and falls back**: it attempts the `VECTOR_SEARCH` query once;
|
|
33
|
+
if the server rejects it, it caches that fact process-wide and routes all subsequent queries through an
|
|
34
|
+
exact **`VECTOR_DISTANCE`** scan. Where the TVF *is* available, filtered queries additionally dispatch
|
|
35
|
+
on cardinality — below a configurable threshold (default 50,000 matching rows) they use the exact path
|
|
36
|
+
anyway, because DiskANN's graph walk fails to converge when a filter's row cluster is disjoint from the
|
|
37
|
+
query vector's neighborhood. Net: correct results everywhere, accelerated where the index exists.
|
|
38
|
+
|
|
39
|
+
### Storage modes
|
|
40
|
+
|
|
41
|
+
Configured per index via `MJVectorIndex.ProviderConfig` (which flows to `CreateIndexParams.additionalParams`):
|
|
42
|
+
|
|
43
|
+
| Mode | Where vectors live | Filters resolve against | Use it for |
|
|
44
|
+
|---|---|---|---|
|
|
45
|
+
| `sibling` (default) | an MJ-managed sibling table (`id`/`embedding`/`metadata`/`content`) | the JSON `metadata` column | generic, entity-agnostic, multi-model indexes |
|
|
46
|
+
| `entityColumn` | an existing `VECTOR` column on an entity table | **live entity columns** | adopting embeddings already stored on a table — no re-vectorization |
|
|
47
|
+
|
|
48
|
+
#### `entityColumn` configuration
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"storageMode": "entityColumn",
|
|
53
|
+
"sourceTable": "Recommendation.Content",
|
|
54
|
+
"vectorColumn": "Embedding",
|
|
55
|
+
"keyColumn": "ID",
|
|
56
|
+
"entityName": "Content",
|
|
57
|
+
"selectColumns": ["Title", "URL", "Source", "ContentType", "Date"],
|
|
58
|
+
"iterativeFilterThreshold": 50000
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The provider projects the listed columns into each result's metadata and synthesizes the MJ
|
|
63
|
+
`RecordID`/`Entity` fields so the `SearchEngine` renders these results identically to sibling/external
|
|
64
|
+
indexes. `entityColumn` upsert/delete operate by a single scalar key (`keyColumn`); composite-PK
|
|
65
|
+
entities are not supported in this mode.
|
|
66
|
+
|
|
67
|
+
## Enabling
|
|
68
|
+
|
|
69
|
+
1. Create an `MJ: Vector Databases` row with `ClassKey = 'SQLServerVectorDatabase'` (no `DefaultURL`
|
|
70
|
+
or `CredentialID` — it uses the application's connection).
|
|
71
|
+
2. Create `MJ: Vector Indexes` rows pointing at it, with the `ProviderConfig` above for `entityColumn`
|
|
72
|
+
mode (or none for `sibling` mode).
|
|
73
|
+
3. Search flows through `@memberjunction/search-engine`'s `VectorSearchProvider`; sync flows through
|
|
74
|
+
`@memberjunction/ai-vector-sync`'s `EntityVectorSyncer`.
|
|
75
|
+
|
|
76
|
+
## Limitations
|
|
77
|
+
|
|
78
|
+
- Requires **SQL Server 2025** (major version ≥ 17); the provider fails loud on older servers.
|
|
79
|
+
- **Approximate / DiskANN search** depends on the `VECTOR_SEARCH` TVF, which is absent on boxed
|
|
80
|
+
SQL Server 2025 RTM (the provider transparently falls back to exact `VECTOR_DISTANCE` — correct,
|
|
81
|
+
but O(rows) per query, so large corpora on the boxed product will be slow until a CU adds the TVF).
|
|
82
|
+
- **Hybrid keyword search** (full-text `CONTAINS` + vector) is not yet implemented — queries are
|
|
83
|
+
vector-only. (The pgvector colocated provider does RRF hybrid today.)
|
|
84
|
+
- `entityColumn` mode supports **single-column keys** only.
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
ISC
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { BaseRequestParams, BaseResponse, ColocatedQueryOptions, ColocatedQueryResult, CreateIndexParams, EditIndexParams, IndexList, ListVectorIDsParams, ListVectorIDsResult, QueryOptions, SharedIndexFilterOptions, UpdateOptions, VectorDBBase, VectorRecord } from '@memberjunction/ai-vectordb';
|
|
2
|
+
import { UserInfo } from '@memberjunction/core';
|
|
3
|
+
/**
|
|
4
|
+
* Colocated MemberJunction vector provider backed by **SQL Server 2025 native vectors**
|
|
5
|
+
* (`VECTOR(N)` + the `VECTOR_SEARCH` DiskANN table-valued function), stored in the application's
|
|
6
|
+
* own database. Borrows the active data provider's connection via {@link IColocatedVectorHost}.
|
|
7
|
+
*
|
|
8
|
+
* **Two storage modes** (per index, via `MJVectorIndex.ProviderConfig` → `CreateIndexParams.additionalParams`):
|
|
9
|
+
* - `sibling` (default): MJ creates and owns a sibling table (`id`/`embedding`/`metadata`/`content`).
|
|
10
|
+
* Generic, entity-agnostic, multi-model. Filters resolve against the JSON `metadata` column.
|
|
11
|
+
* - `entityColumn`: vectors live on an existing entity table's `VECTOR` column. Filters resolve
|
|
12
|
+
* against **live entity columns**, and results project real entity fields. This is the migration
|
|
13
|
+
* target for systems that already store embeddings on their own tables (e.g. a `Content.Embedding`
|
|
14
|
+
* column) — point MJ at the column instead of re-vectorizing.
|
|
15
|
+
*
|
|
16
|
+
* **Query path** prefers the DiskANN-aware `VECTOR_SEARCH` TVF (never `ORDER BY VECTOR_DISTANCE`,
|
|
17
|
+
* which doesn't engage the index). But that surface isn't in every 2025 build — verified live, boxed
|
|
18
|
+
* SQL Server 2025 RTM lacks it — so the provider lazily detects (per host) whether `VECTOR_SEARCH`
|
|
19
|
+
* works and **falls back to an exact `VECTOR_DISTANCE` scan** when it doesn't. Where the TVF exists,
|
|
20
|
+
* filtered queries dispatch on cardinality: small filtered sets use the exact path (DiskANN doesn't
|
|
21
|
+
* converge when the filter cluster is disjoint from the query neighborhood), large sets use DiskANN.
|
|
22
|
+
* See {@link sqlserverColocatedSQL} for the production-verified SQL shapes and the reasoning behind each.
|
|
23
|
+
*
|
|
24
|
+
* Validated end-to-end against a live SQL Server 2025 RTM container in sibling and entityColumn modes
|
|
25
|
+
* (exact fallback path). The approximate path on Azure SQL Database remains untested.
|
|
26
|
+
*
|
|
27
|
+
* Registered with the MJ class factory as `'SQLServerVectorDatabase'`.
|
|
28
|
+
*/
|
|
29
|
+
export declare class SQLServerVectorDatabase extends VectorDBBase {
|
|
30
|
+
constructor(apiKey: string);
|
|
31
|
+
get SupportsColocatedQuery(): boolean;
|
|
32
|
+
get SupportsHybridSearch(): boolean;
|
|
33
|
+
private get Host();
|
|
34
|
+
private get Schema();
|
|
35
|
+
private Qualify;
|
|
36
|
+
private Run;
|
|
37
|
+
private AssertVectorCapable;
|
|
38
|
+
private EnsureInfrastructure;
|
|
39
|
+
private GetResolvedIndex;
|
|
40
|
+
/** Validate & narrow the untyped `CreateIndexParams.additionalParams` bag into a typed config,
|
|
41
|
+
* throwing on malformed shapes rather than asserting (`as`) a shape that may not hold. */
|
|
42
|
+
private NormalizeIndexConfig;
|
|
43
|
+
private ParseSelectColumns;
|
|
44
|
+
/** Resolve the schema-qualified table string for an entityColumn source spec, validating each
|
|
45
|
+
* identifier segment (accepts `[schema].[table]`, `schema.table`, or bare `table`). */
|
|
46
|
+
private QualifyEntityTable;
|
|
47
|
+
ListIndexes(): Promise<IndexList>;
|
|
48
|
+
GetIndex(params: BaseRequestParams): Promise<BaseResponse>;
|
|
49
|
+
CreateIndex(params: CreateIndexParams): Promise<BaseResponse>;
|
|
50
|
+
private CreateSiblingIndex;
|
|
51
|
+
private RegisterEntityColumnIndex;
|
|
52
|
+
/** Attempt to create a DiskANN vector index; tolerate failure (preview surface / pre-existing). */
|
|
53
|
+
private TryCreateVectorIndex;
|
|
54
|
+
private UpsertRegistry;
|
|
55
|
+
DeleteIndex(params: BaseRequestParams): Promise<BaseResponse>;
|
|
56
|
+
EditIndex(_params: EditIndexParams): Promise<BaseResponse>;
|
|
57
|
+
/**
|
|
58
|
+
* Whether a given host server supports the `VECTOR_SEARCH` DiskANN TVF
|
|
59
|
+
* (`SELECT TOP (N) WITH APPROXIMATE`). Verified live: boxed **SQL Server 2025 RTM does NOT** —
|
|
60
|
+
* only `VECTOR_DISTANCE` (exact) ships there; the approximate/DiskANN surface is currently Azure
|
|
61
|
+
* SQL Database (and likely a later boxed CU). Detected lazily on first query.
|
|
62
|
+
*
|
|
63
|
+
* Keyed **per host**, not process-wide: one MJ process can hold connections to multiple SQL
|
|
64
|
+
* Servers (parallel client-to-many-servers, or mixed 2022/2025 backends), and capability differs
|
|
65
|
+
* per server — a process-global flag would let one server's probe poison another's path.
|
|
66
|
+
*/
|
|
67
|
+
private static ApproximateSearchSupportedByHost;
|
|
68
|
+
ColocatedQuery(params: ColocatedQueryOptions, _contextUser?: UserInfo): Promise<ColocatedQueryResult>;
|
|
69
|
+
/**
|
|
70
|
+
* Execute the vector search, choosing the exact vs. approximate path and transparently falling
|
|
71
|
+
* back to exact `VECTOR_DISTANCE` when this server lacks the `VECTOR_SEARCH` TVF.
|
|
72
|
+
*
|
|
73
|
+
* Path selection:
|
|
74
|
+
* - If the approximate surface is known-absent → always exact.
|
|
75
|
+
* - Else for filtered queries, count the filter cardinality and use exact below the threshold
|
|
76
|
+
* (DiskANN doesn't converge when the filter cluster is disjoint from the query neighborhood).
|
|
77
|
+
* - Else attempt approximate; if it errors with a "feature not supported" signature, cache that
|
|
78
|
+
* fact and retry exact.
|
|
79
|
+
*/
|
|
80
|
+
private RunVectorQuery;
|
|
81
|
+
/** Best-effort heuristic: does this error indicate the VECTOR_SEARCH/DiskANN surface is absent on
|
|
82
|
+
* this server? Matches on message text (brittle across CUs/locales), but only gates a fallback to
|
|
83
|
+
* an equally-correct exact query, so a false negative just rethrows and a false positive is slow,
|
|
84
|
+
* not wrong. */
|
|
85
|
+
private IsApproximateUnsupportedError;
|
|
86
|
+
/** Map a query result row to a ColocatedMatch, synthesizing metadata per storage mode. */
|
|
87
|
+
private RowToMatch;
|
|
88
|
+
private ToMetadataValue;
|
|
89
|
+
QueryIndex(params: QueryOptions, contextUser?: UserInfo): Promise<BaseResponse>;
|
|
90
|
+
CreateRecord(record: VectorRecord, indexName?: string): Promise<BaseResponse>;
|
|
91
|
+
CreateRecords(records: VectorRecord[], indexName?: string): Promise<BaseResponse>;
|
|
92
|
+
private UpsertRecords;
|
|
93
|
+
/** Extract the scalar key value from a vector record id (CompositeKey URL `Field|Value`). */
|
|
94
|
+
private ExtractKeyValue;
|
|
95
|
+
UpdateRecord(record: UpdateOptions): Promise<BaseResponse>;
|
|
96
|
+
UpdateRecords(records: UpdateOptions): Promise<BaseResponse>;
|
|
97
|
+
DeleteRecord(record: VectorRecord, indexName?: string): Promise<BaseResponse>;
|
|
98
|
+
DeleteRecords(records: VectorRecord[], indexName?: string): Promise<BaseResponse>;
|
|
99
|
+
private DeleteByKeys;
|
|
100
|
+
DeleteAllRecords(indexName: string, _namespace?: string): Promise<BaseResponse>;
|
|
101
|
+
GetRecord(params: BaseRequestParams): Promise<BaseResponse>;
|
|
102
|
+
GetRecords(params: BaseRequestParams): Promise<BaseResponse>;
|
|
103
|
+
ListVectorIDs(params: ListVectorIDsParams): Promise<ListVectorIDsResult>;
|
|
104
|
+
BuildMetadataFilter(options: SharedIndexFilterOptions): object | undefined;
|
|
105
|
+
private ParseMetadata;
|
|
106
|
+
private Success;
|
|
107
|
+
private Failure;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=SQLServerVectorDatabase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SQLServerVectorDatabase.d.ts","sourceRoot":"","sources":["../../src/models/SQLServerVectorDatabase.ts"],"names":[],"mappings":"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"}
|