Note
This tutorial is valid for versions ≥0.2.0
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:
During creation the HNSW parameters for an index can be configured (see HNSW Parameters). For this tutorial we will keep them to the default values.
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/docs \
-H "Content-Type: application/json" \
-d '{
"data": [
{ "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: Remove docs¶
Remove docs from the index
curl -X POST http://localhost:8080/indexes/products/docs \
-H "Content-Type: application/json" \
-d '{
"data": [ { "id": "prod-001" }, { "id": "prod-009" } ]
}'
Step 7: Update (upsert) docs¶
Define docs to update
curl -X POST http://localhost:8080/indexes/products/docs \
-H "Content-Type: application/json" \
-d '{
"data": [
{ "id": "prod-003", "doc": { "category": "clothing", "colour": "green" } },
{ "id": "prod-004", "doc": { "category": "clothing", "colour": "green" } }
]
}'
Step 8: Delete index¶
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/docs \
-H "Content-Type: application/json" \
-d '{
"data": [
{
"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 |
|---|---|---|
| List indexes | GET |
/indexes |
| Create index | PUT |
/indexes/{indexName} |
| Get index | GET |
/indexes/{indexName} |
| Delete index | DELETE |
/indexes/{indexName} |
| Search | POST |
/indexes/{indexName}/search |
| List docs | GET |
/indexes/{indexName}/docs |
| Create, update, delete docs | POST |
/indexes/{indexName}/docs |
| Get server status | GET |
/status |
Info
When creating/updating/deleting docs, you may specify policies, e.g. policy: { duplicate: "Ignore", missing: "Fail" }, which change the behaviour when values are missing/duplicates. The allowable values are Ignore, Fail for both policies, and additionally Replace is allowed for the duplicate policy. The default duplicate policy is Replace, and the default missing policy is Ignore.
Note
To delete with the /indexes/{indexName}/docs endpoint, specify the doc(s) in data with IDs only.
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.
- Perform alterations to the index such as remove/update