Skip to content

Commit 7e619d6

Browse files
committed
fix(temporal): add missing C_TemporalEdge structure and FFI bindings for v0.4.4
- Add C_TemporalEdge ctypes structure definition - Set up sochdb_add_temporal_edge binding in _setup_bindings() - Fix add_temporal_edge method to use C_TemporalEdge directly - Replace incorrect _FFI.lib access with _FFI.get_lib() - Bump version to 0.4.4 Fixes AttributeError: _FFI when calling add_temporal_edge. Tested with examples/25_temporal_graph_embedded.py
1 parent df5596a commit 7e619d6

7 files changed

Lines changed: 264 additions & 7 deletions

File tree

.DS_Store

6 KB
Binary file not shown.

benchmarks/benchmark_results.json

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
{
2+
"timestamp": "2026-01-23T10:30:04.170446",
3+
"config": {
4+
"embedding_model": "text-embedding-3-small",
5+
"dimension": 1536,
6+
"test_sizes": [
7+
100,
8+
1000,
9+
10000
10+
],
11+
"n_queries": 100
12+
},
13+
"results": [
14+
{
15+
"database": "SochDB",
16+
"n_vectors": 100,
17+
"dimension": 1536,
18+
"insert_time_ms": 4.425082999999885,
19+
"insert_rate": 22598.446176038415,
20+
"search_p50_ms": 0.059167000000082126,
21+
"search_p95_ms": 0.06795799999981256,
22+
"search_p99_ms": 0.168665999999984,
23+
"search_qps": 16309.552700731098,
24+
"recall_at_k": null,
25+
"memory_mb": null,
26+
"notes": ""
27+
},
28+
{
29+
"database": "LanceDB",
30+
"n_vectors": 100,
31+
"dimension": 1536,
32+
"insert_time_ms": 11.495457999999736,
33+
"insert_rate": 8699.087935426522,
34+
"search_p50_ms": 5.834291999999408,
35+
"search_p95_ms": 6.270707999999736,
36+
"search_p99_ms": 15.23308399999923,
37+
"search_qps": 167.87505227734113,
38+
"recall_at_k": null,
39+
"memory_mb": null,
40+
"notes": ""
41+
},
42+
{
43+
"database": "FAISS",
44+
"n_vectors": 100,
45+
"dimension": 1536,
46+
"insert_time_ms": 6.4550419999998,
47+
"insert_rate": 15491.765971468985,
48+
"search_p50_ms": 0.0287910000000835,
49+
"search_p95_ms": 0.03187499999945942,
50+
"search_p99_ms": 0.32933300000070886,
51+
"search_qps": 31108.282331333234,
52+
"recall_at_k": null,
53+
"memory_mb": null,
54+
"notes": ""
55+
},
56+
{
57+
"database": "SochDB",
58+
"n_vectors": 1000,
59+
"dimension": 1536,
60+
"insert_time_ms": 58.600166999999814,
61+
"insert_rate": 17064.797784620703,
62+
"search_p50_ms": 0.07791700000048252,
63+
"search_p95_ms": 0.110040999999228,
64+
"search_p99_ms": 0.19212499999987642,
65+
"search_qps": 12094.149080484322,
66+
"recall_at_k": null,
67+
"memory_mb": null,
68+
"notes": ""
69+
},
70+
{
71+
"database": "LanceDB",
72+
"n_vectors": 1000,
73+
"dimension": 1536,
74+
"insert_time_ms": 42.4589589999993,
75+
"insert_rate": 23552.15538845445,
76+
"search_p50_ms": 6.608124999999632,
77+
"search_p95_ms": 7.051208000000031,
78+
"search_p99_ms": 8.041625000000607,
79+
"search_qps": 149.95792750394492,
80+
"recall_at_k": null,
81+
"memory_mb": null,
82+
"notes": ""
83+
},
84+
{
85+
"database": "FAISS",
86+
"n_vectors": 1000,
87+
"dimension": 1536,
88+
"insert_time_ms": 15.313291000000007,
89+
"insert_rate": 65302.749095540574,
90+
"search_p50_ms": 0.04945799999944711,
91+
"search_p95_ms": 0.061917000000022426,
92+
"search_p99_ms": 0.0789589999996565,
93+
"search_qps": 19753.410278121868,
94+
"recall_at_k": null,
95+
"memory_mb": null,
96+
"notes": ""
97+
},
98+
{
99+
"database": "SochDB",
100+
"n_vectors": 10000,
101+
"dimension": 1536,
102+
"insert_time_ms": 710.5952499999972,
103+
"insert_rate": 14072.708760718622,
104+
"search_p50_ms": 0.17445900000723213,
105+
"search_p95_ms": 0.230333999994059,
106+
"search_p99_ms": 0.27979200000061155,
107+
"search_qps": 5589.8702160549765,
108+
"recall_at_k": null,
109+
"memory_mb": null,
110+
"notes": ""
111+
},
112+
{
113+
"database": "LanceDB",
114+
"n_vectors": 10000,
115+
"dimension": 1536,
116+
"insert_time_ms": 471.4319579999966,
117+
"insert_rate": 21211.968833050712,
118+
"search_p50_ms": 11.561083999993116,
119+
"search_p95_ms": 11.90204099999903,
120+
"search_p99_ms": 17.021958000000836,
121+
"search_qps": 85.75038964183328,
122+
"recall_at_k": null,
123+
"memory_mb": null,
124+
"notes": ""
125+
},
126+
{
127+
"database": "FAISS",
128+
"n_vectors": 10000,
129+
"dimension": 1536,
130+
"insert_time_ms": 243.22812500000168,
131+
"insert_rate": 41113.66643968468,
132+
"search_p50_ms": 0.10487500000522232,
133+
"search_p95_ms": 0.13204100000052676,
134+
"search_p99_ms": 0.18179100000281778,
135+
"search_qps": 9384.387026347129,
136+
"recall_at_k": null,
137+
"memory_mb": null,
138+
"notes": ""
139+
}
140+
]
141+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
{
2+
"timestamp": "2026-01-23T10:28:05.417398",
3+
"config": {
4+
"embedding_model": "text-embedding-3-small",
5+
"dimension": 1536,
6+
"n_documents": 1000,
7+
"n_queries": 50
8+
},
9+
"embedding_stats": {
10+
"api_calls": 2,
11+
"cache_hits": 2100,
12+
"cache_size": 1050
13+
},
14+
"results": [
15+
{
16+
"database": "SochDB",
17+
"dimension": 1536,
18+
"n_documents": 1000,
19+
"insert_time_ms": 58.67583399999976,
20+
"insert_rate": 17042.79141562784,
21+
"search_p50_ms": 0.18912500000034527,
22+
"search_p95_ms": 0.2679999999992688,
23+
"search_p99_ms": 0.6289580000000683,
24+
"search_qps": 5084.163755219192,
25+
"batch_search": {
26+
"1": {
27+
"total_ms": 0.18049999999991684,
28+
"per_query_ms": 0.18049999999991684,
29+
"qps": 5540.166204988702
30+
},
31+
"10": {
32+
"total_ms": 1.4779579999997239,
33+
"per_query_ms": 0.1477957999999724,
34+
"qps": 6766.092135231088
35+
},
36+
"50": {
37+
"total_ms": 6.873917000000063,
38+
"per_query_ms": 0.13747834000000125,
39+
"qps": 7273.873106119778
40+
}
41+
},
42+
"filtered_search_supported": false,
43+
"filtered_search_note": "",
44+
"memory_mb": 154.3125,
45+
"status": "success"
46+
},
47+
{
48+
"database": "ChromaDB",
49+
"dimension": 1536,
50+
"n_documents": 1000,
51+
"status": "error",
52+
"error": "\u001b[91mYou are using a deprecated configuration of Chroma.\n\n\u001b[94mIf you do not have data you wish to migrate, you only need to change how you construct\nyour Chroma client. Please see the \"New Clients\" section of https://docs.trychroma.com/deployment/migration.\n________________________________________________________________________________________________\n\nIf you do have data you wish to migrate, we have a migration tool you can use in order to\nmigrate your data to the new Chroma architecture.\nPlease `pip install chroma-migrate` and run `chroma-migrate` to migrate your data and then\nchange how you construct your Chroma client.\n\nSee https://docs.trychroma.com/deployment/migration for more information or join our discord at https://discord.gg/MMeYNTmh3x for help!\u001b[0m"
53+
},
54+
{
55+
"database": "Qdrant",
56+
"dimension": 1536,
57+
"n_documents": 1000,
58+
"insert_time_ms": 853.6975000000009,
59+
"insert_rate": 1171.3751065219226,
60+
"status": "error",
61+
"error": "'QdrantClient' object has no attribute 'search'"
62+
},
63+
{
64+
"database": "FAISS",
65+
"dimension": 1536,
66+
"n_documents": 1000,
67+
"insert_time_ms": 19.18970800000075,
68+
"insert_rate": 52111.267143823185,
69+
"search_p50_ms": 0.05029200000095102,
70+
"search_p95_ms": 0.06391700000030198,
71+
"search_p99_ms": 0.13787500000006503,
72+
"search_qps": 18835.93897153092,
73+
"batch_search": {
74+
"1": {
75+
"total_ms": 0.054625000000640966,
76+
"per_query_ms": 0.054625000000640966,
77+
"qps": 18306.6361553916
78+
},
79+
"10": {
80+
"total_ms": 0.4843329999992818,
81+
"per_query_ms": 0.04843329999992818,
82+
"qps": 20646.951580864465
83+
},
84+
"50": {
85+
"total_ms": 2.504957999999391,
86+
"per_query_ms": 0.05009915999998782,
87+
"qps": 19960.41450595665
88+
}
89+
},
90+
"filtered_search_supported": false,
91+
"filtered_search_note": "",
92+
"memory_mb": 253.765625,
93+
"status": "success"
94+
}
95+
]
96+
}

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "sochdb"
7-
version = "0.4.3"
7+
version = "0.4.4"
88
description = "SochDB is an AI-native database with token-optimized output, O(|path|) lookups, built-in vector search, and durable transactions."
99
readme = "README.md"
1010
license = {text = "Apache-2.0"}

src/sochdb/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
client.put_kv("key", b"value")
3333
"""
3434

35-
__version__ = "0.4.3"
35+
__version__ = "0.4.4"
3636

3737
# Embedded mode (FFI)
3838
from .database import Database, Transaction

src/sochdb/database.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,18 @@ class C_SearchResult(ctypes.Structure):
177177
]
178178

179179

180+
class C_TemporalEdge(ctypes.Structure):
181+
"""Temporal edge structure for add_temporal_edge."""
182+
_fields_ = [
183+
("from_id", ctypes.c_char_p),
184+
("edge_type", ctypes.c_char_p),
185+
("to_id", ctypes.c_char_p),
186+
("valid_from", ctypes.c_uint64),
187+
("valid_until", ctypes.c_uint64),
188+
("properties_json", ctypes.c_char_p),
189+
]
190+
191+
180192
class _FFI:
181193
"""FFI bindings to the native library."""
182194

@@ -356,6 +368,14 @@ def _setup_bindings(cls):
356368

357369
# Temporal Graph API
358370
try:
371+
# sochdb_add_temporal_edge(ptr, ns, edge) -> c_int
372+
lib.sochdb_add_temporal_edge.argtypes = [
373+
ctypes.c_void_p, # ptr
374+
ctypes.c_char_p, # namespace
375+
C_TemporalEdge, # edge
376+
]
377+
lib.sochdb_add_temporal_edge.restype = ctypes.c_int
378+
359379
# sochdb_query_temporal_graph(ptr, ns, node, mode, ts, start, end, type, out_len)
360380
lib.sochdb_query_temporal_graph.argtypes = [
361381
ctypes.c_void_p,
@@ -1931,12 +1951,11 @@ def add_temporal_edge(
19311951

19321952
import json
19331953

1934-
# Use the C_TemporalEdge structure from FFI
1935-
# (defined in _FFI class)
19361954
# Convert properties to JSON
19371955
props_json = None if properties is None else json.dumps(properties).encode("utf-8")
19381956

1939-
edge = _FFI.lib.sochdb_add_temporal_edge.argtypes[2]( # Get C_TemporalEdge class
1957+
# Create C_TemporalEdge structure
1958+
edge = C_TemporalEdge(
19401959
from_id=from_id.encode("utf-8"),
19411960
edge_type=edge_type.encode("utf-8"),
19421961
to_id=to_id.encode("utf-8"),
@@ -1945,8 +1964,8 @@ def add_temporal_edge(
19451964
properties_json=props_json,
19461965
)
19471966

1948-
result = _FFI.lib.sochdb_add_temporal_edge(
1949-
self._ptr,
1967+
result = _FFI.get_lib().sochdb_add_temporal_edge(
1968+
self._handle,
19501969
namespace.encode("utf-8"),
19511970
edge
19521971
)

test_temporal_db/.clean_shutdown

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
clean

0 commit comments

Comments
 (0)