vd.time_indexed#
Time-indexed vector collection wrapper.
Wraps any vd Collection and adds an in-memory sorted (timestamp, id)
index, enabling efficient retrieval by time window, fixed-window aggregation
(daily/hourly buckets), and time-bounded semantic search.
The wrapper is backend-agnostic: it works with any object that satisfies the
vd Collection protocol (MutableMapping + search). Timestamps are
stored as ISO-8601 strings in document metadata, so backend-side metadata
filtering keeps working (e.g. ChromaDB’s $gte filter on a string field
sorts correctly because ISO-8601 is lexicographically ordered).
Examples
>>> from vd import connect, Document
>>> import hashlib
>>> def fake_embed(t): # 8-dim deterministic toy embedding
... return [b / 128.0 - 1.0 for b in hashlib.md5(t.encode()).digest()[:8]]
>>> client = connect('memory', embedder=fake_embed)
>>> news = TimeIndexedCollection(client.create_collection('news'))
>>> news['a'] = Document(id='a', text='Earnings miss',
... metadata={'ts': '2025-03-13T09:00:00'})
>>> news['b'] = Document(id='b', text='Profit warning',
... metadata={'ts': '2025-03-13T15:30:00'})
>>> news['c'] = Document(id='c', text='Tariffs announced',
... metadata={'ts': '2025-03-14T08:00:00'})
>>> [d.id for d in news.query_window('2025-03-13', '2025-03-14')]
['a', 'b']
>>> # Count documents per day
>>> [(s.date().isoformat(), v) for s, _, v in
... news.window_iter(window='1d', reducer=len)]
[('2025-03-13', 2), ('2025-03-14', 1)]
Functions
|
|
|
Element-wise mean of document embeddings. |
|
Parse a window spec into a |
|
Coerce a timestamp-like value into a tz-aware UTC |
|
ISO-8601 (UTC) string suitable for cross-backend metadata storage. |
Classes
|
Time-indexed wrapper over any vd |
|
A time window: |
- class vd.time_indexed.TimeIndexedCollection(collection, *, ts_field='ts', ts_parser=<function to_datetime>)[source]#
Bases:
MutableMappingTime-indexed wrapper over any vd
Collection.Maintains a sorted
(ts_epoch, id)index alongside the underlying collection. Each stored document MUST carry a timestamp in its metadata underts_field(default"ts"). The stored value is normalized to an ISO-8601 string so backend-side filtering remains usable.- Parameters:
collection (
MutableMapping) – Any vd Collection (MutableMapping +search).ts_field (
str) – Metadata key holding the timestamp.ts_parser (
Callable[[Any],datetime]) – Optional custom parserAny -> datetime. Defaults toto_datetime().
Notes
The index is rebuilt on construction from whatever the underlying collection already contains (so the wrapper is safe to re-wrap a persisted collection across process restarts).
- property base: MutableMapping#
The wrapped underlying collection.
- query_window(start=None, end=None, *, filt=None)[source]#
Yield documents with
start <= ts < end, in chronological order.start/endmay beNonefor half-open infinity.filtis an optional MongoDB-style predicate applied to document metadata, evaluated client-side (so it works on any backend).
- reindex()[source]#
Force-rebuild the in-memory time index from the underlying collection.
- Return type:
- search_window(query, *, start=None, end=None, limit=10, filt=None, **kwargs)[source]#
Semantic search restricted to a time window.
Builds a metadata filter on
ts_fieldand delegates to the underlying collection’ssearch. Falls back to a client-side post-filter for backends that don’t honor the filter.
- time_range()[source]#
Return
(min_ts, max_ts)as aware datetimes, or None if empty.>>> from vd import connect, Document >>> import hashlib >>> emb = lambda t: [b/128.0-1.0 for b in hashlib.md5(t.encode()).digest()[:4]] >>> col = connect('memory', embedder=emb).create_collection('t') >>> t = TimeIndexedCollection(col) >>> t['a'] = Document(id='a', text='x', metadata={'ts': '2025-01-01'}) >>> t['b'] = Document(id='b', text='y', metadata={'ts': '2025-03-01'}) >>> [d.isoformat() for d in t.time_range()] ['2025-01-01T00:00:00+00:00', '2025-03-01T00:00:00+00:00']
- window_iter(window='1d', *, start=None, end=None, reducer=<function count_docs>, skip_empty=False, align=True)[source]#
Yield
(window_start, window_end, reducer_value)over fixed windows.- Parameters:
window (
Union[str,timedelta,int,float]) – Window size. Seeparse_window()for accepted forms.start (
Union[str,datetime,int,float,None]) – Override the data range. Default: actual min/max ts in the index.end (
Union[str,datetime,int,float,None]) – Override the data range. Default: actual min/max ts in the index.reducer (
Callable[[Iterable[Document]],Any]) – Callable taking the iterable of in-window ``Document``s. Default iscount_docs(). See alsomean_vector().skip_empty (
bool) – If True, omit windows that contained zero documents.align (
bool) – If True (default), alignstartto the previous midnight (for daily windows) or towindow-rounded boundary so downstream joins are clean. If False, use the literalstart.
- Return type:
- vd.time_indexed.count_docs(docs)[source]#
lenreducer that also handles generator inputs.- Return type:
>>> count_docs(iter([1, 2, 3])) 3
- vd.time_indexed.mean_vector(docs)[source]#
Element-wise mean of document embeddings.
Noneif empty / no vectors.>>> from vd.base import Document >>> mean_vector([ ... Document(id='a', text='', vector=[1.0, 2.0]), ... Document(id='b', text='', vector=[3.0, 4.0]), ... ]) [2.0, 3.0] >>> mean_vector([]) is None True
- vd.time_indexed.parse_window(window)[source]#
Parse a window spec into a
timedelta.Strings use a trailing unit char:
"1d","4h","30m","15s","1w". Numbers are treated as seconds. Atimedeltais returned as-is.- Return type:
>>> parse_window('1d') == timedelta(days=1) True >>> parse_window('4h') == timedelta(hours=4) True >>> parse_window(3600) == timedelta(hours=1) True
- vd.time_indexed.to_datetime(ts)[source]#
Coerce a timestamp-like value into a tz-aware UTC
datetime.Accepts ISO-8601 strings (with or without timezone), date-only strings (
"2025-03-13"), epoch seconds (int or float), anddatetimeobjects. Naive datetimes / strings are assumed UTC.- Return type:
>>> to_datetime('2025-03-13T09:00:00').isoformat() '2025-03-13T09:00:00+00:00' >>> to_datetime('2025-03-13').isoformat() '2025-03-13T00:00:00+00:00' >>> to_datetime(1741856400).isoformat() '2025-03-13T09:00:00+00:00'