Tutorial¶
In this tutorial you will create an index, train it with sample data, and perform searches — all using curl against the Aspected REST API.
Prerequisites¶
- Aspected is running on
http://localhost:8080(see Getting Started). - If you want to follow the text-resolver section, make sure GGUF models are available (see Text Resolver).
Part 1 — Enum-only Index¶
We will build a simple product catalogue index using only enum resolvers. No model downloads are required for this part.
Step 1: Create the Index¶
Create an index called products with two enum aspects — category and colour:
curl -X PUT http://localhost:8080/indexes/products \
-H "Content-Type: application/json" \
-d '{
"idSize": 36,
"aspects": [
{
"name": "category",
"type": "enum",
"path": "$.category",
"settings": {
"values": ["electronics", "clothing", "food", "furniture", "toys"]
}
},
{
"name": "colour",
"type": "enum",
"path": "$.colour",
"settings": {
"values": ["red", "green", "blue", "black", "white", "yellow"]
}
}
]
}'
Expected response:
Step 2: Inspect the Index¶
Retrieve the index metadata to see the computed dimensions and HNSW parameters:
The response will include the full schema, the total number of dimensions (the sum of dimensions produced by each resolver), and the default HNSW configuration.
Step 3: Train the Index¶
Insert some sample products:
curl -X POST http://localhost:8080/indexes/products/train \
-H "Content-Type: application/json" \
-d '{
"rows": [
{ "id": "prod-001", "doc": { "category": "electronics", "colour": "black" } },
{ "id": "prod-002", "doc": { "category": "electronics", "colour": "white" } },
{ "id": "prod-003", "doc": { "category": "clothing", "colour": "red" } },
{ "id": "prod-004", "doc": { "category": "clothing", "colour": "blue" } },
{ "id": "prod-005", "doc": { "category": "food", "colour": "green" } },
{ "id": "prod-006", "doc": { "category": "furniture", "colour": "white" } },
{ "id": "prod-007", "doc": { "category": "toys", "colour": "red" } },
{ "id": "prod-008", "doc": { "category": "toys", "colour": "yellow"} },
{ "id": "prod-009", "doc": { "category": "electronics", "colour": "blue" } },
{ "id": "prod-010", "doc": { "category": "furniture", "colour": "black" } }
]
}'
Expected response:
Each document is passed through the resolvers: the category field is extracted via $.category and mapped to a radial embedding by the enum resolver, and the same happens for colour. The two embeddings are concatenated to form the stored vector.
Step 4: Search — Single Aspect¶
Search for products in the electronics category. We only specify the category aspect, so the colour dimensions are treated as sparse (ignored):
curl -X POST http://localhost:8080/indexes/products/search \
-H "Content-Type: application/json" \
-d '{
"k": 5,
"query": {
"category": "electronics"
}
}'
The response returns the nearest neighbours ranked by distance:
{
"data": [
{ "id": "prod-001", "distance": 0.0 },
{ "id": "prod-002", "distance": 0.0 },
{ "id": "prod-009", "distance": 0.0 },
{ "id": "prod-003", "distance": 0.29 },
{ "id": "prod-004", "distance": 0.29 }
],
"status": "ok"
}
All three electronics products appear first with a distance of 0 (exact match on that aspect).
Step 5: Search — Multiple Aspects¶
Now search for red toys — specifying both aspects:
curl -X POST http://localhost:8080/indexes/products/search \
-H "Content-Type: application/json" \
-d '{
"k": 3,
"query": {
"category": "toys",
"colour": "red"
}
}'
prod-007 (a red toy) should appear first with the smallest distance.
Step 6: Clean Up¶
Delete the index when you are done:
Part 2 — Adding a Text Resolver¶
This part extends the example by adding a text aspect for semantic search on product descriptions.
Model required
Make sure you have downloaded at least one GGUF embedding model and mounted it into the container. See Text Resolver — Downloading Models.
Step 1: Create the Index¶
Create a catalogue index with an enum aspect for category and a text aspect for description:
curl -X PUT http://localhost:8080/indexes/catalogue \
-H "Content-Type: application/json" \
-d '{
"idSize": 36,
"aspects": [
{
"name": "category",
"type": "enum",
"path": "$.category",
"settings": {
"values": ["electronics", "clothing", "outdoor", "kitchen"],
"multiplier": 5.0
}
},
{
"name": "description",
"type": "text",
"path": "$.description",
"settings": {
"model": "nomic-embed-text-v1.5.f16.gguf",
"multiplier": 1.0
}
}
]
}'
Warning
The first time a model is used, Aspected loads it into memory. This may take a few seconds depending on the model size. Subsequent requests using the same model are instant.
Step 2: Train the Index¶
Feed some products with both a category and a free-text description:
curl -X POST http://localhost:8080/indexes/catalogue/train \
-H "Content-Type: application/json" \
-d '{
"rows": [
{
"id": "item-001",
"doc": {
"category": "electronics",
"description": "Wireless noise-cancelling headphones with 30-hour battery life"
}
},
{
"id": "item-002",
"doc": {
"category": "electronics",
"description": "Portable Bluetooth speaker, waterproof and dustproof"
}
},
{
"id": "item-003",
"doc": {
"category": "clothing",
"description": "Lightweight waterproof running jacket with reflective strips"
}
},
{
"id": "item-004",
"doc": {
"category": "outdoor",
"description": "Compact camping tent for two people, easy to set up"
}
},
{
"id": "item-005",
"doc": {
"category": "outdoor",
"description": "Insulated stainless steel water bottle, keeps drinks cold for 24 hours"
}
},
{
"id": "item-006",
"doc": {
"category": "kitchen",
"description": "Non-stick frying pan with ceramic coating"
}
}
]
}'
Step 3: Semantic Search¶
Search for products using only a text description — ignore the category entirely:
curl -X POST http://localhost:8080/indexes/catalogue/search \
-H "Content-Type: application/json" \
-d '{
"k": 3,
"query": {
"description": "something to keep my drinks warm or cold"
}
}'
The text resolver converts the query into an embedding and finds the most semantically similar items. You should see item-005 (the insulated water bottle) near the top.
Step 4: Combined Search¶
Search for outdoor items that are related to water:
curl -X POST http://localhost:8080/indexes/catalogue/search \
-H "Content-Type: application/json" \
-d '{
"k": 3,
"query": {
"category": "outdoor",
"description": "water"
}
}'
This combines the enum match on category with the semantic match on description, so results must be close on both aspects.
Step 5: Clean Up¶
Summary¶
| Action | Method | Endpoint |
|---|---|---|
| Create index | PUT |
/indexes/{id} |
| Get index | GET |
/indexes/{id} |
| List indexes | GET |
/indexes |
| Delete index | DELETE |
/indexes/{id} |
| Train | POST |
/indexes/{id}/train |
| Search | POST |
/indexes/{id}/search |
| Check exists | GET |
/indexes/{id}/exists |
You now know how to:
- Define an index schema using the available resolvers (
enum,text,number,datetime, andraw). - Train the index with structured documents.
- Perform sparse searches on any combination of aspects.