# one quick embedding → get true vector dimension dim=len(mistr.embeddings(model=MODEL,input=["ping"]).data[0].embedding)
schema=""" DEFINE TABLE $tb SCHEMALESS PERMISSIONS NONE; DEFINE FIELD text ON $tb TYPE string; DEFINE FIELD embedding ON $tb TYPE array;
DEFINE INDEX hnsw_idx ON $tb FIELDS embedding HNSW DIMENSION {dim} DIST COSINE; """ awaitsdb.query(schema,{"tb": TABLE})
asyncio.run(init_db())
Why detect the dimension dynamically?
Future-proofing: if Mistral introduces a small or large Embed model with a different dimension, the code auto-adapts.
Embed and bulk-insert documents
DOCS=[ "SurrealDB offers an in-memory HNSW vector index for low-latency search.", "Mistral-Embed produces 1 024-dimensional embeddings.", "You can build a completely open-source RAG stack with these two tools.", ]
Why bulk-insert? One SurrealQL call → one network round-trip — much faster than inserting row-by-row.
Search with a natural-language query
asyncdefsearch(query: str,k: int=3,ef: int=64): q_vec=mistr.embeddings(model=MODEL,input=[query]).data[0].embedding surql=""" LET $q := $vec; SELECT id, text, vector::distance::knn() AS score FROM $tb WHERE embedding <|{k},{ef}|> $q ORDER BY score; """ res=awaitsdb.query(surql,{"vec": q_vec,"tb": TABLE}) returnres[0].result
DOCS=[ "SurrealDB's vector index is built on HNSW.", "Mistral-Embed vectors offer strong semantic quality.", "Together they form a fast, open-source search stack.", ]
dim=len(mistr.embeddings(model=MODEL,input=["x"]).data[0].embedding) awaitsdb.query(""" DEFINE TABLE $tb SCHEMALESS PERMISSIONS NONE; DEFINE FIELD text ON $tb TYPE string; DEFINE FIELD embedding ON $tb TYPE array; DEFINE INDEX hnsw_idx ON $tb FIELDS embedding HNSW DIMENSION {dim} DIST COSINE; """,{"tb": TABLE})
# ingest if empty if(awaitsdb.query(f"SELECT count() FROM {TABLE};"))[0].result[0]["count"]==0: rows=[] vecs=mistr.embeddings(model=MODEL,input=DOCS).data rows=[ {"id": f"{TABLE}:{i}","text": DOCS[i],"embedding": v.embedding} fori,vinenumerate(vecs) ] awaitsdb.query(f"INSERT INTO {TABLE} $data",{"data": rows})
# search q_vec=mistr.embeddings(model=MODEL, input=["open-source vector database"]).data[0].embedding res=awaitsdb.query(""" LET $q := $vec; SELECT text, vector::distance::knn() AS score FROM {TABLE} WHERE embedding <|3,64|> $q ORDER BY score; """,{"vec": q_vec}) print(res[0].result)
if__name__=="__main__": asyncio.run(main())
About quantisation
SurrealDB currently stores vectors as float32 / float64 arrays and does not ship built-in binary or int8 quantisation.
If memory is critical you can:
Quantise offline to int8 (e.g. with faiss or sentence-transformers).
Store the int8 arrays in another field (SurrealQL’s array type is agnostic).
Execute a two-stage search: coarse K-NN on the int8 field, then rescore on the full-precision field.
You’re done 🚀
You now have a clean, fully-async SurrealDB setup that stores Mistral-Embed vectors, supports fast HNSW search, and can be dropped into any RAG or semantic-search workflow.