typesense / typesense/typesense
Facet by a nested join field leads to issues
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 26.6k
- Forks
- 973
- Avg merge
- 18h 45m
- Merged PRs (30d)
- 4
Description
Bug Description
When you have a data model with multiple joins (product -> variant -> stock), faceting on the nested joins (e.g. a property 'inStock' on the Stock level) leads to timeouts/cancelled requests.
Reproduction Steps
@hostname = localhost:46675
@apiKey = typesense-api-key
DELETE http://{{hostname}}/collections/products
X-TYPESENSE-API-KEY: {{ApiKey}}
###
DELETE http://{{hostname}}/collections/variants
X-TYPESENSE-API-KEY: {{ApiKey}}
###
DELETE http://{{hostname}}/collections/stock
X-TYPESENSE-API-KEY: {{ApiKey}}
### Create Products Collection.
POST http://{{hostname}}/collections
X-TYPESENSE-API-KEY: {{apiKey}}
Content-Type: application/json
{
"name": "products",
"fields": [
{"name": "name", "type": "string", "facet": false, "sort": true},
{"name": "brand", "type": "string", "facet": true, "sort": true}
],
"metadata": {"revision": "d9765d97-91a8-4042-bbdf-50697f0876ed"}
}
### Create Alias for Products.
PUT http://{{hostname}}/aliases/productsalias
X-TYPESENSE-API-KEY: {{apiKey}}
Content-Type: application/json
{
"collection_name": "products"
}
### Create Variants Collection.
POST http://{{hostname}}/collections
X-TYPESENSE-API-KEY: {{apiKey}}
Content-Type: application/json
{
"name": "variants",
"fields": [
{"name": "product_id", "type": "string", "facet": true, "reference": "productsalias.id", "async_reference": true},
{"name": "color", "type": "string", "facet": true, "sort": true}
],
"metadata": {"revision": "8a8793bf-7592-48fc-ac14-ab0896bc9ba0"}
}
### Create Alias for Variants.
PUT http://{{hostname}}/aliases/variantsalias
X-TYPESENSE-API-KEY: {{apiKey}}
Content-Type: application/json
{
"collection_name": "variants"
}
### Create Stock Collection.
POST http://{{hostname}}/collections
X-TYPESENSE-API-KEY: {{apiKey}}
Content-Type: application/json
{
"name": "stock",
"fields": [
{"name": "variant_id", "type": "string", "reference": "variantsalias.id"},
{"name": "inStock", "type": "bool", "facet": true, "sort": true}
]
}
### Create Alias for Stock.
PUT http://{{hostname}}/aliases/stockalias
X-TYPESENSE-API-KEY: {{apiKey}}
Content-Type: application/json
{
"collection_name": "stock"
}
### Index Products.
POST http://{{hostname}}/collections/productsalias/documents/import?action=upsert
X-TYPESENSE-API-KEY: {{apiKey}}
Content-Type: application/json
{"id":"p-1","name":"Product 1","brand":"A"}
{"id":"p-2","name":"Product 2","brand":"A"}
{"id":"p-3","name":"Product 3","brand":"B"}
{"id":"p-4","name":"Product 4","brand":"C"}
### Index Variants.
POST http://{{hostname}}/collections/variantsalias/documents/import?action=upsert
X-TYPESENSE-API-KEY: {{apiKey}}
Content-Type: application/json
{"id":"p-1-v-1","product_id":"p-1","color":"Red"}
{"id":"p-1-v-2","product_id":"p-1","color":"Green"}
{"id":"p-1-v-3","product_id":"p-1","color":"Blue"}
{"id":"p-2-v-1","product_id":"p-2","color":"Pink"}
{"id":"p-2-v-2","product_id":"p-2","color":"Red"}
{"id":"p-3-v-1","product_id":"p-3","color":"Red"}
{"id":"p-3-v-2","product_id":"p-3","color":"Blue"}
{"id":"p-4-v-1","product_id":"p-4","color":"Red"}
### Index Stock.
POST http://{{hostname}}/collections/stockalias/documents/import?action=upsert
X-TYPESENSE-API-KEY: {{apiKey}}
Content-Type: application/json
{"id":"p-1-v-1-s-1","variant_id":"p-1-v-1","inStock":true}
{"id":"p-1-v-2-s-2","variant_id":"p-1-v-2","inStock":false}
{"id":"p-4-v-1-s-1","variant_id":"p-4-v-1","inStock":true}
### Facet on 'inStock'
POST http://{{hostname}}/multi_search
X-TYPESENSE-API-KEY: {{apiKey}}
Content-Type: application/json
{
"searches": [
{
"collection": "productsalias",
"q": "*",
"filter_by": "id:* || $variantsalias(id:*) || $variantsalias($stockalias(id:*))",
"facet_by": "brand, $variantsalias(color), $variantsalias($stockalias(inStock))",
"per_page": 5
}
]
}
The last '$variantsalias($stockalias(inStock))' in facet_by is the part which leads to issues.
As an alternative I tested the following query, which returns no facet values for 'inStock':
{
"searches": [
{
"collection": "productsalias",
"q": "*",
"filter_by": "id:* || $variantsalias(id:*) || $variantsalias($stockalias(id:*))",
"facet_by": "brand, $variantsalias(color), $stockalias(inStock)",
"per_page": 5
}
]
}
Expected vs Actual
Expected behavior
The correct facet values and facet counts should be returned.
Actual behavior
Typesense does not respond.
Environment
- Typesense version: e.g.
v30.1
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the provided multi_search reproduction against Typesense v30.1, focusing on nested facet handling for $variantsalias($stockalias(inStock)). Trace the nested-join faceting path and compare it with the alternative query. Done means the request responds and returns the correct inStock facet values and counts.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- search
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100