Performance tuning
This topic describes performance tuning recommendations for the PolarDB-X intelligent search engine in terms of index design, data ingestion, and queries.
Index design optimization
Shard count planning
A shard is the basic unit of data distribution and parallel processing. Planning the shard count properly is critical to performance.
|
Data volume |
Recommended shard count |
Description |
|
< 10 GB |
1 |
A single shard is sufficient. Avoid the overhead of over-sharding. |
|
10 GB to 50 GB |
2 to 3 |
A moderate shard count balances query parallelism and management overhead. |
|
50 GB to 200 GB |
3 to 5 |
Keep each shard between 30 GB and 50 GB. |
|
> 200 GB |
Calculate based on 30 GB to 50 GB per shard |
Avoid oversized single shards that increase query latency. |
Key principles:
-
Keep each shard between 30 GB and 50 GB.
-
The shard count should not exceed the node count multiplied by 20.
-
The shard count cannot be modified after index creation, so plan ahead.
-
Too many shards increase cluster metadata overhead and coordination cost.
Replica count selection
|
Scenario |
Replica count |
Description |
|
Development and testing |
0 |
Save resources. High availability is not required. |
|
Standard production |
1 |
Ensure high availability. Tolerates 1 node failure. |
|
High availability requirement |
2 |
Tolerates up to 2 simultaneous node failures. |
|
Read-intensive workloads |
1 to 2 |
Replicas help distribute read traffic. |
The replica count can be adjusted dynamically without rebuilding the index.
Mapping design best practices
curl -XPUT "http://<Search engine address>:<port>/my-index" \
-u "<username>:<password>" -k \
-H "Content-Type: application/json" \
-d '{
"settings": { "index.mapping.total_fields.limit": 1000 },
"mappings": {
"dynamic": "strict",
"properties": {
"title": { "type": "text", "analyzer": "ik_max_word" },
"status": { "type": "keyword" },
"price": { "type": "float" },
"created_at": { "type": "date" }
}
}
}'
-
Set
"dynamic": "strict"to disallow automatically adding undefined fields and prevent mapping bloat. -
For fields that do not need to be searched, set
"index": falseto reduce indexing overhead. -
Do not add a
keywordsubfield totextfields that are not used for aggregation or sorting. -
Use
keywordinstead oftextfor exact-match fields. -
Choose the appropriate numeric type for numeric fields. Do not use
longfor all numbers.
Disable unnecessary features
|
Setting |
Effect |
When to disable |
|
|
Disable length normalization factor |
Fields not used for relevance-based sorting |
|
|
Disable columnar storage |
Fields not used for sorting or aggregation |
|
|
Disable indexing |
Fields that only need to be stored but not searched |
|
|
Do not store separately |
Already contained in |
Write performance optimization
Bulk write configuration
-
Size per
_bulkrequest: 5 MB to 15 MB. Larger sizes cause memory pressure. -
Documents per request: 1,000 to 5,000, depending on document size.
-
Concurrent write threads: 2 to 4, adjusted based on the CPU core count of the node.
Index settings tuning during writes
Before importing a large batch of data, temporarily adjust index settings to boost write throughput:
# Before writing: disable replicas and increase the refresh interval
curl -XPUT "http://<Search engine address>:<port>/my-index/_settings" \
-u "<username>:<password>" -k \
-H "Content-Type: application/json" \
-d '{
"number_of_replicas": 0,
"refresh_interval": "-1",
"translog.durability": "async",
"translog.flush_threshold_size": "1gb"
}'
# === Run the bulk data import ===
# After writing: restore normal settings
curl -XPUT "http://<Search engine address>:<port>/my-index/_settings" \
-u "<username>:<password>" -k \
-H "Content-Type: application/json" \
-d '{
"number_of_replicas": 1,
"refresh_interval": "1s",
"translog.durability": "request"
}'
curl -XPOST "http://<Search engine address>:<port>/my-index/_refresh" -u "<username>:<password>" -k
curl -XPOST "http://<Search engine address>:<port>/my-index/_forcemerge?max_num_segments=1" -u "<username>:<password>" -k
Query performance optimization
Avoid deep pagination
// Not recommended: deep pagination performs poorly
{ "from": 10000, "size": 10 }
// Recommended: use search_after
{
"size": 10,
"sort": [ { "created_at": "desc" }, { "_id": "asc" } ],
"search_after": ["2025-05-25T10:00:00Z", "doc_id_123"]
}
Use filter context appropriately
A filter clause does not participate in scoring and can leverage caching, delivering better performance than must. Place any condition that does not need to affect relevance scoring inside a filter.
Limit returned fields
{
"query": { "match": { "content": "search" } },
"_source": ["title", "summary", "created_at"],
"size": 10
}
Avoid returning large fields such as full-text content or vector embedding. Return only the fields required for display.
Avoid expensive queries
-
Leading wildcard
*abc: use areverse token filterorngram. -
Complex
script_score: use precomputed fields. -
Deeply nested
nested query: denormalize the schema. -
Large numbers of
shouldclauses (> 100): use aterms query. -
match_allwith a largesize: use pagination orscroll.
Vector search optimization
Vector dimension selection
|
Model |
Dimensions |
Memory per million documents |
Suitable scenarios |
|
Small model |
128 to 256 |
~0.5 GB to 1 GB |
Lightweight scenarios such as recommendation and classification |
|
General-purpose model |
768 |
~3 GB |
General-purpose semantic search |
|
Large model |
1024 to 1536 |
~4 GB to 6 GB |
High-precision semantic or multimodal search |
HNSW parameter tuning
|
Parameter |
Default |
Description |
|
|
100 |
Recommended value is 128 to 512. Increases accuracy but also increases indexing time. |
|
|
16 |
Recommended value is 8 to 32. Represents the maximum number of connections per node. |
|
|
100 |
Set dynamically through query parameters. |
Key metrics to monitor
# Node resource usage
curl -XGET "http://<Search engine address>:<port>/_cat/nodes?v&h=name,heap.percent,ram.percent,cpu,disk.used_percent" \
-u "<username>:<password>" -k
# Thread pool (pay attention to rejected)
curl -XGET "http://<Search engine address>:<port>/_cat/thread_pool?v&h=node_name,name,active,queue,rejected" \
-u "<username>:<password>" -k
Performance alert threshold reference:
-
CPU utilization > 80% warning / > 90% critical: scale out or optimize queries.
-
Disk utilization > 75% warning / > 85% critical: a full disk turns indexes read-only.