Function Memoization Keys
CocoIndex memoizes (caches) results using a stable, deterministic key derived from CocoIndex function call’s inputs.
How CocoIndex derives keys
For each argument value, CocoIndex derives a “key fragment” with this precedence:
- If the object implements
__coco_memo_key__(), CocoIndex uses its return value. - Otherwise, if you registered a memo key function for the object’s type, CocoIndex uses that.
- Otherwise, CocoIndex falls back to structural canonicalization for a limited set of primitives/containers.
The final memoization key is a deterministic fingerprint of the full call key.
Define __coco_memo_key__ (preferred when you control the type)
Implement a method on your class:
class MyType:
def __coco_memo_key__(self) -> object:
# Must return a stable, deterministic value across processes.
# Prefer small primitives / tuples.
return (...)
What should you return?
Return something that uniquely identifies the semantic content your function depends on.
- Good: small tuples of primitives, e.g.
(stable_id, version) - Bad: memory addresses, unstable UUIDs, open file handles, timestamps “now”, or large raw payloads
Examples
File-like resource (include freshness):
import os
from pathlib import Path
class LocalFile:
def __init__(self, path: Path) -> None:
self.path = path
def __coco_memo_key__(self) -> object:
p = self.path.resolve()
st = os.stat(p)
return (str(p), st.st_mtime_ns, st.st_size)
DB row (include row version / updated_at):
class UserRow:
def __init__(self, user_id: int, updated_at: int) -> None:
self.user_id = user_id
self.updated_at = updated_at
def __coco_memo_key__(self) -> object:
return ("users", self.user_id, self.updated_at)
Register a key function for a type (when you don’t control the type)
If you can’t add __coco_memo_key__ (stdlib / third-party types), register a handler:
from cocoindex import register_memo_key_function
def path_key(p) -> object:
p = p.resolve()
st = p.stat()
return (str(p), st.st_mtime_ns, st.st_size)
register_memo_key_function(__import__("pathlib").Path, path_key)
Notes:
- Registration is MRO-aware: if you register both a base class and a subclass, the most specific match wins.
- Your key function must return the same kinds of stable objects as
__coco_memo_key__(small primitives/tuples).
Best practices
- Always include freshness for external resources: e.g. file
(path, mtime_ns, size), HTTP(url, etag), DB(pk, updated_at). - Keep keys small: use identifiers + versions, not full payloads.
- Keys must be deterministic across processes: no
id(obj), no pointer addresses, no random values.