Use when writing any IRIS vector search, embedding, HNSW index, similarity search, or AI feature code. Hard gate — IRIS vector syntax is completely different from pgvector.
설치
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
Use when writing any IRIS vector search, embedding, HNSW index, similarity search, or AI feature code. Hard gate — IRIS vector syntax is completely different from pgvector.
iris_version
>=2024.1
license
MIT
metadata
{"baseline_pass_rate":1,"benchmark_note":"Source inspection suite. Negative lift on unrelated tasks when loaded globally. Load on-demand for vector/AI tasks. RED phase: model plagiarizes pgvector syntax 100% without this skill.","lift":0,"red_phase":"12 prompts tested — model plagiarizes pgvector syntax 100% of the time without this skill","version":"1.0.0"}
IRIS vector syntax is NOT pgvector. Stop. Read this before writing any vector code.
HARD GATE
VECTOR column: VECTOR(DOUBLE, 384) — type AND dimension required, not just vector(384)
HNSW index: AS HNSW(Distance='Cosine') — NOT USING hnsw (col vector_cosine_ops)
Distance parameter: 'Cosine' or 'DotProduct' only — NOT 'l2', 'euclidean', 'inner_product'
HNSW tuning params are exactly M and efConstruction — spelled efConstruction, NOT efConstruct, NOT ef_construction
efSearch is NOT a AS HNSW(...) parameter — it is a runtime property on %SQL.VectorIndex.HNSWIndexer, not settable in DDL. Passing it to AS HNSW(...) fails the CREATE INDEX.
Similarity function: VECTOR_COSINE(a, b) — NOT <=> or <-> operators
Parameter binding: TO_VECTOR(?, DOUBLE, 384) — 3 args: value, type, dimension. NOT casting with ::vector. The type and dimension MUST match the column definition.
NEVER SELECT a VECTOR column directly — the DB-API driver returns it as a plain str (comma-separated floats). Use VECTOR_COSINE() or VECTOR_DOT_PRODUCT() in the SQL; never try to deserialize the raw column value as a list or array.
TO_VECTOR type mismatch causes SQLCODE -259 — TO_VECTOR(?) with no type arg creates a different internal datatype than TO_VECTOR(?, DOUBLE, 384). Always pass all 3 args. Mismatched type (e.g., DOUBLE vs FLOAT) or dimension causes "different datatypes" or "different lengths" errors even when the content looks the same.
Step 4 — if the raw DDL fails even after the key check, the error is in the SQL syntax:
Both type and dimension are required: VECTOR(DOUBLE, N)
N must be a literal integer, not a variable
The type must match everywhere it is referenced — column DDL, TO_VECTOR(), index
The HNSW index must be a separate DDL statement, NOT inline in CREATE TABLE
The exact false-alarm pattern
// Framework code called VectorStore.Build(), which internally calls CreateTable().
// CreateTable() generated an invalid SQL class definition, the IRIS class compiler
// failed, and the failure surfaced as #15806 "Vector Search not permitted".
// ACTUAL CAUSE: syntax error in the generated DDL, not a license problem.
%AI.RAG.VectorStore.IRIS.Build() // -> #15806
// but, at the same time, on the same instance:
CREATE TABLE Test.V (v VECTOR(DOUBLE,3)) // -> SQLCODE: 0
The container had vector search. The %AI.RAG.VectorStore framework had a bad DDL template.
VECTOR Column and Index
-- CORRECT IRIS syntax (NOT pgvector):CREATE TABLE Company.People (
Name VARCHAR(100),
Biography VECTOR(DOUBLE, 384) -- type + dimension required
)
-- CORRECT HNSW index:CREATE INDEX HNSWIdx ONTABLE Company.People (Biography)
AS HNSW(Distance='Cosine')
-- With tuning params (defaults on %SQL.Index.HNSW: Distance=Cosine, M=16, efConstruction=64):CREATE INDEX HNSWIdx ONTABLE Company.People (Biography)
AS HNSW(M=32, efConstruction=200, Distance='DotProduct')
-- WRONG (misspelled param — SQLCODE -400, ERROR #5480 Index parameter not declared):CREATE INDEX HNSWIdx ONTABLE Company.People (Biography)
AS HNSW(M=32, efConstruct=200)
-- WRONG (efSearch is a runtime indexer property, not a DDL parameter):CREATE INDEX HNSWIdx ONTABLE Company.People (Biography)
AS HNSW(efSearch=100)
-- WRONG (pgvector syntax — does NOT work in IRIS):CREATE INDEX ON embeddings USING hnsw (embedding vector_cosine_ops);
CREATE INDEX ON t USING hnsw (col) WITH (m=16, ef_construction=64);
ProjectMap and SUPPORTSPARTITIONING also exist on %SQL.Index.HNSW but are framework
internals — not tuning knobs.
Failed CREATE INDEX looks exactly like an inert index
A rejected CREATE INDEX leaves the table with no vector index. Downstream that is
indistinguishable from an index that exists but has an empty HNSW graph: every query does a
full scan, results are still correct, only slow. This ambiguity burned ~9.5 hours in one real
debugging session. Check both sides:
-- 1. Never ignore the SQLCODE from CREATE INDEX itself.-- SQLCODE=-400 / ERROR #5480 "Index parameter not declared: <Class>:<Idx>:EFCONSTRUCT"-- means the index was never created.-- 2. Confirm the index actually exists:SELECT Name, TypeClass, Parameters FROM%Dictionary.CompiledIndex
WHERE parent ='Company.People'
Similarity Search
-- CORRECT: TOP N nearest neighborsSELECT TOP 5 Name, VECTOR_COSINE(Biography, TO_VECTOR(?, DOUBLE, 384)) AS score
FROM Company.People
ORDERBY score DESC-- Embedding() generates vector from text using configured model:SELECT TOP 5 Name
FROM Company.People
ORDERBY VECTOR_COSINE(Biography, EMBEDDING('myconfig', ?)) DESC-- WRONG (pgvector operators — don't exist in IRIS):SELECT*FROM items ORDERBY embedding <=>'[1,2,3]'::vector LIMIT 5;
TOP N + ORDER BY is what activates the HNSW index
An HNSW index that exists is not an HNSW index that runs. The query shape decides. Without
ORDER BY <score> DESC the optimizer has nothing to feed the ANN pass, so it full-scans and
computes VECTOR_COSINE for every row — correct results, index bypassed.
-- WRONG: full table scan, HNSW index NOT usedSELECT node_id, VECTOR_COSINE(vec, TO_VECTOR(?, DOUBLE, 384)) AS score
FROM MyTable
WHERE visibility ='global'-- CORRECT: HNSW activated by TOP N + ORDER BY score DESCSELECT TOP 10 node_id, VECTOR_COSINE(vec, TO_VECTOR(?, DOUBLE, 384)) AS score
FROM MyTable
WHERE visibility ='global'ORDERBY score DESC-- REQUIRED — without this, HNSW is bypassed
Pre-filtering with WHERE ahead of the ORDER BY is correct and efficient — it narrows the
candidate set before the HNSW ANN pass.
Driver Behavior — What the DB-API Returns
VECTOR columns come back as plain str through the iris.dbapi driver. Always. No exceptions.
cur.execute("SELECT embedding FROM MyTable WHERE id = 1")
row = cur.fetchone()
# row[0] is a str: "0.1,0.2,0.3,..." — NOT a list, NOT a numpy array, NOT bytes# type(row[0]) == str ← this is permanent, not a bug, not fixable
Never do this:
# WRONG — will fail or silently corrupt
vec = list(row[0]) # gives list of chars, not floats
vec = np.array(row[0]) # gives array of one string
vec = json.loads(row[0]) # JSON parse error (no brackets)
Correct pattern — never SELECT the raw vector; compute similarity in SQL:
# RIGHT — always use VECTOR_COSINE / VECTOR_DOT_PRODUCT in SQL
cur.execute("""
SELECT TOP 5 id, VECTOR_COSINE(embedding, TO_VECTOR(?, DOUBLE, 384)) AS score
FROM MyTable
ORDER BY score DESC
""", ["0.1,0.2,..."]) # pass query vector as comma-separated string
If you must retrieve a stored vector as Python floats:
# Convert in SQL, not in Python
cur.execute("SELECT VECTOR_TOARRAY(embedding) FROM MyTable WHERE id=1")
# Returns a comma-separated string you can then parse:
floats = [float(x) for x in row[0].split(",")]
TO_VECTOR Type Contract
TO_VECTOR creates a typed vector. The type and dimension must exactly match the column definition or SQLCODE -259 fires.
# Column defined as VECTOR(DOUBLE, 384)# CORRECT:
TO_VECTOR(?, DOUBLE, 384) # type=DOUBLE, dim=384 — matches column# WRONG — causes SQLCODE -259 "different datatypes":
TO_VECTOR(?) # no type/dim — different internal type
TO_VECTOR(?, FLOAT, 384) # FLOAT ≠ DOUBLE — different datatype
TO_VECTOR(?, DOUBLE, 128) # 128 ≠ 384 — different lengths
In tests/fixtures: if a test table was created with dimension 128 and the query uses 768, the test is broken by design — no amount of driver magic fixes a dimension mismatch. Fix the test fixture to match the query dimension, or make dimension a configurable constant.
Inserting Vectors
-- From a comma-separated string:INSERT INTO Company.People (Name, Biography)
VALUES ('Alice', TO_VECTOR('[0.1,0.2,...]', DOUBLE, 384))
-- Python iris.dbapi:
cur.execute("INSERT INTO People (Name, Biography) VALUES (?,TO_VECTOR(?,DOUBLE,384))",
["Alice", "0.1,0.2,..."]) -- pass as string without brackets, not list
Version Matrix
Feature
Min IRIS version
Notes
VECTOR datatype
2024.1
Works in Community Edition
VECTOR_COSINE(), VECTOR_DOT_PRODUCT()
2024.1
SIMD-accelerated
HNSW index (AS HNSW(...))
2025.1
ANN search
EMBEDDING() SQL function
2025.1
Requires %Embedding.Config
%Library.Embedding class
2025.1
$VECTOROP global operation
2025.3
Batch operations
Sharded HNSW
2026.2
Compute/data separation
Embedded Python (%SYS.Python)
// CORRECT:
Set pd = ##class(%SYS.Python).Import("pandas")
Set df = pd.DataFrame(data)
// Method written in Python:
Method Analyze() [ Language = python ]
{
import iris
return iris.cls("MyClass").GetData()
}
// WRONG (these don't exist):
Set py = ##class(IRIS.Python).New()
Do py.Execute("import pandas")
%AI.RAG.VectorStore.IRIS — What the API Actually Is
Do NOT assume methods exist on this class without verifying. It ships roughly five
ObjectScript methods; the rest of its advertised capability comes from a Rust bridge binary and
only exists in specific builds.
// Methods confirmed on %AI.RAG.VectorStore.IRIS (2026.2.0 AI builds):
// Build(fields) -- creates table + HNSW index via the Rust bridge
// Cleanup() -- drops the table
// CreateTable(fields) -- internal; called by Build()
// %OnClose -- destructor
// %OnNew -- constructor
// Methods that do NOT exist on VectorStore:
// AddDocument() -- lives on %AI.RAG.KnowledgeBase
// Search() -- lives on %AI.RAG.KnowledgeBase
// UpdateMetadata() -- does not exist at all; update via raw SQL
%AI.RAG.KnowledgeBase is a RAG document-chunking layer. It is the wrong primitive for typed
records with their own fields (confidence, usefulness, expiry, and so on) — use raw VECTOR SQL
tables for those.
If Build() returns #15806 and your raw VECTOR DDL works fine, the Rust bridge template has a DDL
bug for your specific field configuration. Bypass VectorStore and manage the table schema yourself
with raw SQL.
Requires IRIS 2021.2+. Python environment must be configured (see iris-connectivity skill).