Collections
Collections are the object stores where your data lives. Every object you upsert belongs to a collection. A collection declares a set of named, typed fields. Each object then carries values for any subset of those fields.
Field Types
A collection is created from a list of field definitions. Endee supports three field types, which you can freely combine in one collection:
| Type | Purpose | Required keys | params |
|---|---|---|---|
vector | Dense semantic search (one vector per object) | name, type | dimension, space_type, precision (+ optional M, ef_con) |
sparse | Keyword / BM25 search | name, type, sparse_model | — (no params) |
multi_vector | Many vectors per object, pooled for retrieval (e.g. ColBERT) | name, type | dimension, space_type, precision, pooling ("mean"/"max") (+ optional M, ef_con) |
Dense Collections
A dense vector field enables semantic search: finding items based on meaning rather than exact keyword matches. Each object’s value is a list of numbers, one per dimension, representing the meaning of your content.
Use a dense field when you want to:
- Find semantically similar documents
- Power recommendation systems
- Enable image/video similarity search
Python
from endee import Endee
client = Endee("your-serverless-token")
client.create_collection(
name="my_collection",
fields=[
{
"name": "embedding",
"type": "vector",
"params": {"dimension": 384, "space_type": "cosine", "precision": "int16"},
},
],
)Hybrid Collections
Add a sparse field alongside a dense vector field to combine semantic similarity with keyword matching (BM25). You query both fields and fuse the results, giving you the best of both worlds: meaning and exact terms.
Use a hybrid collection for:
- Document retrieval in RAG pipelines
- Search where both meaning and keywords matter
- Any use case where dense-only search misses exact terminology
Python
client.create_collection(
name="hybrid_collection",
fields=[
{
"name": "embedding",
"type": "vector",
"params": {"dimension": 384, "space_type": "cosine", "precision": "int16"},
},
{"name": "keywords", "type": "sparse", "sparse_model": "endee_bm25"},
],
)The endee-model BM25 sparse embedding library is currently available for Python and TypeScript only. Java supports hybrid collections using the default sparse model. Bring your own sparse vectors generated from any BM25 implementation.
See the Sparse Vectors (BM25) guide for installing endee-model and generating BM25 embeddings for Python and Typescript.
Sparse Model Options:
sparse_model | Description |
|---|---|
default | Bring your own sparse vectors (you provide final indices and values). Use for SPLADE or any custom model. |
endee_bm25 | Use Endee’s BM25 model via the endee-model package. Endee holds the IDF weights server-side and applies them automatically, so you only send TF weights. |
The sparse_model parameter
sparse_model="endee_bm25": use this when your sparse vectors come fromendee/bm25. Endee holds the IDF weights on its server and applies them automatically, so you only need to send the TF weights from your client.sparse_model="default": use this for SPLADE models or any other BM25 model. Endee treats the values you send as final scores and does no further calculation. If you use a different BM25 model (notendee/bm25), compute the full IDF scores yourself on the client before sending them.
Multi-Vector Collections
A multi_vector field stores several vectors per object (for example, one per token or passage) and pools them into a single vector for retrieval. Two pooling strategies are supported:
mean: elementwise average of the membersmax: elementwise maximum of the members
Python
client.create_collection(
name="passages",
fields=[
{
"name": "embedding",
"type": "vector",
"params": {"dimension": 384, "space_type": "cosine", "precision": "int8"},
},
{
"name": "colbert",
"type": "multi_vector",
"params": {"dimension": 384, "space_type": "cosine", "precision": "int8", "pooling": "mean"},
},
],
)Field Parameters
For vector and multi_vector fields, the params object configures dimensionality, distance, quantization, and HNSW build behavior:
| Parameter | Description | Default |
|---|---|---|
dimension | Dense vector dimensionality (max 10,000) | Required |
space_type | Distance metric: cosine, l2, or ip (inner product) | cosine |
precision | Vector quantization level (see Precision) | int8 |
pooling | Pooling strategy for multi_vector fields: mean or max | Required (multi-vector) |
M | HNSW graph connectivity (higher = better recall, more memory) | 16 |
ef_con | HNSW build-time quality parameter (higher = better quality, slower build) | 128 |
Python
# All vector params explicitly set
client.create_collection(
name="my_collection",
fields=[
{
"name": "embedding",
"type": "vector",
"params": {
"dimension": 768,
"space_type": "cosine",
"precision": "float32",
"M": 32, # higher connectivity = better recall, more memory
"ef_con": 200, # higher = better index quality, slower build
},
},
],
)Distance Metrics
Choose the appropriate distance metric based on your embedding model and use case:
| Metric | Value | Description | Best For |
|---|---|---|---|
| Cosine | cosine | Measures the angle between vectors (direction only) | Text embeddings, normalized vectors |
| L2 | l2 | Euclidean distance (magnitude and direction) | Image embeddings, spatial data |
| Inner Product | ip | Dot product similarity | Maximum inner product search (e.g., recommendation) |
Most embedding models (e.g., Sentence Transformers, OpenAI) produce normalized embeddings. Use cosine by default. Endee L2-normalizes cosine vectors client-side before sending.
HNSW Algorithm
Dense and multi-vector fields use the HNSW (Hierarchical Navigable Small World) algorithm for Approximate Nearest Neighbor (ANN) search. The two build-time parameters (M and ef_con) control the quality vs. memory/build-time trade-off.
| Parameter | Effect of Increasing |
|---|---|
M | Higher recall, more memory usage |
ef_con | Better index quality, slower build time |
The defaults (M=16, ef_con=128) are good starting points for most workloads.
ef_con is a build-time parameter set when creating the collection; it controls index quality and cannot be changed without rebuilding the field. ef_search is a separate query-time parameter that controls how many candidates are explored per search. The two are independent. See Search: Search Parameters.
Collection Management
List Collections
Python
collections = client.list_collections()
for col in collections:
print(col)Get Collection
Returns a handle to an existing collection for searching and upserting.
Python
collection = client.get_collection("my_collection")Describe Collection
Returns the collection’s field definitions and metadata.
Python
info = collection.describe() # {name, fields, created_at, layout_version}Delete Collection
Deletion is irreversible. All objects in the collection are permanently removed.
Python
client.delete_collection("my_collection")Collection Maintenance
Rebuild
Rebuild one or more dense vector fields’ HNSW graphs to apply new M / ef_con values. Rebuild runs asynchronously. See Rebuild for the full API, polling pattern, and status response shape.
Shrink
Defragment the collection’s storage in place.
Python
collection.shrink() # {"status": "ok", "reclaimed_bytes": <int>}