{"id":38183957,"url":"https://github.com/antarys-ai/antarys","last_synced_at":"2026-01-17T00:00:23.458Z","repository":{"id":296368807,"uuid":"990067241","full_name":"antarys-ai/antarys","owner":"antarys-ai","description":"Python client for Antarys vector database, optimized for large-scale vector operations with built-in caching, parallel processing, and dimension validation.","archived":false,"fork":false,"pushed_at":"2025-10-06T15:03:03.000Z","size":36741,"stargazers_count":236,"open_issues_count":0,"forks_count":3,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-01T14:19:10.794Z","etag":null,"topics":["llm","machine-learning","rag","search","vector-database","vector-search"],"latest_commit_sha":null,"homepage":"http://antarys.ai/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/antarys-ai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-05-25T12:40:48.000Z","updated_at":"2025-10-26T13:55:37.000Z","dependencies_parsed_at":"2025-05-30T12:13:38.018Z","dependency_job_id":"d61f37f5-bac7-4110-b079-c34ccfffc13b","html_url":"https://github.com/antarys-ai/antarys","commit_stats":null,"previous_names":["antarys-ai/antarys-python","antarys-ai/antarys"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/antarys-ai/antarys","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antarys-ai%2Fantarys","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antarys-ai%2Fantarys/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antarys-ai%2Fantarys/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antarys-ai%2Fantarys/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/antarys-ai","download_url":"https://codeload.github.com/antarys-ai/antarys/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antarys-ai%2Fantarys/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28489785,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T23:55:29.509Z","status":"ssl_error","status_checked_at":"2026-01-16T23:55:29.108Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["llm","machine-learning","rag","search","vector-database","vector-search"],"created_at":"2026-01-17T00:00:06.741Z","updated_at":"2026-01-17T00:00:23.310Z","avatar_url":"https://github.com/antarys-ai.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"## [Antarys](https://antarys.ai)\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"./media/antarys.jpg\" alt=\"Antarys\" width=\"400\"/\u003e\n  \n  # Antarys\n  \n  **A hackable vector database for on-demand scaling**\n  \n  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)\n  \n\u003c/div\u003e\n\nHigh-Performance Embeddable Vector Database. [WIP]\n\n## Shards\n\nEverything lives in shards:\n\n```go\ntype ShardedCollectionData struct {\n    Vectors      map[string][]float32  // Your actual vectors\n    Metadata     map[string]any        // embedding metadata you give us\n    HNSWGraph    *hnswGraph           // The search index\n\n    // async channels\n    pendingInserts   chan *pendingInsert\n    hnswUpdateChan   chan *hnswUpdate\n}\n```\n\nHNSW Graphs are responsible for creating connections\n\n```go\ntype hnswGraph struct {\n    Nodes      map[uint32]*hnswNode  // Map of node ID to actual node\n    EntryPoint uint32                // Where to start searches\n    IDToNodeID map[string]uint32     // Your ID -\u003e our internal ID\n}\n\ntype hnswNode struct {\n    ID          string\n    VectorID    string\n    Connections map[int][]uint32      // level -\u003e list of connected nodes\n}\n```\n\n## Async Insertion\n\nHere's where it gets interesting. When you insert a vector:\n\n1. We immediately store it in the `Vectors` map\n2. Return success to you right away\n3. Separately queue an HNSW update\n\n```go\nfunc (shard *ShardedCollectionData) processInsertLockless(insert *pendingInsert) error {\n    // Store the vector right away\n    shard.Mutex.Lock()\n    shard.Vectors[insert.id] = insert.vector\n    shard.Metadata[insert.id] = insert.metadata\n    shard.Mutex.Unlock()\n\n    // Try to queue the HNSW update\n    select {\n    case shard.hnswUpdateChan \u003c- \u0026hnswUpdate{...}:\n        // Great, it's queued\n    default:\n        // channel full\n    }\n\n    return nil\n}\n```\n\nThere's a worker constantly processing these updates:\n\n```go\nfunc (shard *ShardedCollectionData) asyncHNSWWorker() {\n    updateBuffer := make([]*hnswUpdate, 0, 100)\n    ticker := time.NewTicker(10 * time.Millisecond)\n\n    for {\n        select {\n        case update := \u003c-shard.hnswUpdateChan:\n            updateBuffer = append(updateBuffer, update)\n\n            // Process in batches of 100\n            if len(updateBuffer) \u003e= 100 {\n                shard.processBatchHNSWUpdates(updateBuffer)\n                updateBuffer = updateBuffer[:0]\n            }\n\n        case \u003c-ticker.C:\n            // Or every 10ms, whichever comes first\n            if len(updateBuffer) \u003e 0 {\n                shard.processBatchHNSWUpdates(updateBuffer)\n                updateBuffer = updateBuffer[:0]\n            }\n        }\n    }\n}\n```\n\n### Current Limitations\n\nThis approach has some issues with the channel being full, HNSW updates might get lost resulting in search quality loss when search operations kick in. Also a goroutine dump can be triggered if we are reading and writing too much information all at the same time.\n\n## The Future: Contiguous Arrays\n\nThe current approach uses tons of pointers and maps. Every time we search, we're jumping around memory. Not great for performance.\n\nThe plan is to switch to structure-of-arrays - basically flatten everything into contiguous chunks of memory.\n\n### Instead of This\n\n```go\n// Current: nodes scattered in memory\ntype hnswNode struct {\n    ID          string\n    Connections map[int][]uint32  // Pointer to another map\n}\n\nnodes := map[uint32]*hnswNode{  // Pointers everywhere\n    1: \u0026hnswNode{...},\n    2: \u0026hnswNode{...},\n}\n```\n\n### We'll Do This\n\n```go\ntype Graph struct {\n    // All vectors in one big chunk\n    Vectors     [][]float32    // [nodeID][dimension]\n\n    // All edges flattened\n    Edges       []uint32       // [1,2,5,3,7,9,...]\n    EdgeStart   []uint32       // [0,3,6,...] - where each node's edges begin\n    EdgeCount   []uint16       // [3,3,2,...] - how many edges each node has\n\n    // Node info\n    Levels      []uint8        // [2,1,3,...] - max level for each node\n    EntryPoint  uint32\n}\n```\n\n### Why This Is Better\n\n**Cache Friendly**: Instead of chasing pointers, we do sequential reads through arrays.\n\n```go\n// Current: pointer hopping\nfor _, neighbor := range node.Connections[level] {\n    neighborNode := graph.Nodes[neighbor]  // Cache miss\n    distance := similarity(query, neighborNode.Vector)  // Another cache miss\n}\n\n// Future: array walking\nfor i := uint32(0); i \u003c graph.NodeCount; i++ {\n    vector := graph.Vectors[i]           // Sequential access\n    distance := similarity(query, vector) // Cache hit\n}\n```\n\n**SIMD Friendly**: Can process multiple vectors at once at compile time:\n\n```go\n// Process 8 vectors simultaneously\nfor i := 0; i \u003c len(nodeIDs); i += 8 {\n    batch := nodeIDs[i:i+8]\n    similarities := dotProductBatch8(query, graph.Vectors, batch)\n}\n```\n\n### Copy-on-Write for Consistency\n\nTo fix the consistency issues, we'll use immutable snapshots:\n\n```go\ntype Database struct {\n    currentSnapshot  *Graph    // Read from this\n    mutableBuffer    *WriteBuffer // Write to this\n}\n\n// Reads are always consistent\nfunc (db *Database) Search(query []float32) []Result {\n    snapshot := atomic.LoadPointer(\u0026db.currentSnapshot)\n    return searchGraph(snapshot, query)\n}\n\n// Writes accumulate in buffer\nfunc (db *Database) Insert(vector []float32) error {\n    db.buffer.Add(vector)\n\n    // Rebuild when buffer gets big\n    if db.buffer.Size() \u003e threshold {\n        go db.rebuildSnapshot()\n    }\n}\n\n// Atomic swap when ready\nfunc (db *Database) rebuildSnapshot() {\n    newGraph := merge(db.currentSnapshot, db.buffer)\n    atomic.StorePointer(\u0026db.currentSnapshot, newGraph)\n    db.buffer.Clear()\n}\n```\n\n## Memory Layout Example\n\nSay you have 3 vectors with these connections:\n\n- Node 0: connects to [1, 2]\n- Node 1: connects to [0, 2]\n- Node 2: connects to [0, 1]\n\n**Current storage**:\n\n```\nNode0 -\u003e {connections: map[0:[1,2]]} -\u003e malloc'd somewhere\nNode1 -\u003e {connections: map[0:[0,2]]} -\u003e malloc'd somewhere else\nNode2 -\u003e {connections: map[0:[0,1]]} -\u003e malloc'd somewhere else\n```\n\n**Array storage**:\n\n```\nVectors:   [v0_data, v1_data, v2_data]        // Sequential\nEdges:     [1, 2, 0, 2, 0, 1]                // All edges flattened\nEdgeStart: [0, 2, 4]                         // Node 0 starts at 0, Node 1 at 2, etc\nEdgeCount: [2, 2, 2]                         // Each node has 2 edges\n```\n\n## Planned Features\n\nThe following features are in development:\n\n- Contiguous Arrays Architecture\n- Filtered search and payload indexing (HTTP API)\n- Distributed architecture with coordination\n- gRPC support for high-performance RPC\n- Comprehensive observability and monitoring\n- Advanced resource management\n- Hybrid and multi-modal search capabilities\n- Multi-tenancy and security features\n- Enhanced query optimization\n- Advanced collection management\n- Backup and recovery improvements\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantarys-ai%2Fantarys","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fantarys-ai%2Fantarys","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantarys-ai%2Fantarys/lists"}