Sharding (alias feature)
Aliases let you query a collection by an alternative name. With aliases, you can:
-
Switch the underlying collection without changing business code — repoint the alias instead of updating application configuration.
-
Partition time series data automatically — the service creates and expires collections on a schedule based on a time field, so you never provision or clean up partitions manually.
-
Rebuild an index with zero downtime — keep the old alias serving queries while the new collection builds, then flip the alias.
This topic explains how to use the Solr Collections API to create and manage aliases in HBase Search.
Use cases
Manage time series data
When business data is time-sensitive, creating a separate collection per time window reduces single-index size and improves query performance. A time-routed alias handles collection creation and expiration automatically, eliminating manual table management.
Rebuild an index
Point an alias at a new collection while the rebuild runs. Existing queries continue against the old collection. After the rebuild finishes, update the alias — no code changes required.
Standard aliases
A standard alias maps a name to one or more existing collections. Use it to switch the underlying collection without touching business code.
Create a standard alias
curl "http://solrhost:8983/solr/admin/collections?action=CREATEALIAS&name=your_alias_name&collections=your_collection_name_A"
This creates an alias named your_alias_name pointing to your_collection_name_A. The service forwards all query requests to that collection.
Switch the collection an alias points to
curl "http://solrhost:8983/solr/admin/collections?action=ALIASPROP&name=your_alias_name&collections=your_collection_name_B"
After this command runs, the alias points to your_collection_name_B. Business code that references the alias name requires no changes.
Delete a standard alias
curl "http://solrhost:8983/solr/admin/collections?action=DELETEALIAS&name=your_alias_name"
Deleting an alias does not delete the underlying collections.
Time-routed aliases
A time-routed alias automatically creates collections at a fixed interval based on a time field. Use it to partition time series data without manual intervention.
Create a time-routed alias
The following example creates collections every 7 days, starting 30 days ago, and auto-deletes collections older than 90 days.
curl "http://solrhost:8983/solr/admin/collections?action=CREATEALIAS\
&name=test_router_alias\
&router.name=time\
&router.field=your_timestamp_l\
&router.start=NOW-30DAYS/DAY\
&router.interval=%2B7DAY\
&router.autoDeleteAge=/DAY-90DAYS\
&router.maxFutureMs=8640000000\
&create-collection.collection.configName=_indexer_default\
&create-collection.numShards=2"
Parameters:
| Parameter | Value in example | Description |
|---|---|---|
router.name |
time |
Routing strategy. Set to time for time-routed aliases. |
router.field |
your_timestamp_l |
The time field in your documents. Must be of type DATE or LONG. A common value is System.currentTimeMillis(). |
router.start |
NOW-30DAYS/DAY |
Start of the time range for the first collection. |
router.interval |
+7DAY |
How often a new collection is created. |
router.autoDeleteAge |
/DAY-90DAYS |
Age at which collections are automatically deleted. Must represent a longer period than router.start. |
router.maxFutureMs |
8640000000 |
Maximum allowed difference between the value of the your_date_dt field and the current time, in milliseconds. 8640000000 ms = 100 days, so only documents timestamped within the last or next 100 days are written. |
create-collection.collection.configName |
_indexer_default |
Configuration set for new collections. See Update configuration sets. |
create-collection.numShards |
2 |
Number of shards per collection. Default value: 2. |
With the example values, the service:
-
Creates the first collection starting 30 days ago.
-
Creates a new collection every 7 days based on the
your_timestamp_lfield. -
Accepts documents timestamped within 100 days (past or future) of now.
-
Deletes collections that are 90 days old.
Business data must include a time field of typeDATEorLONG. By default, queries run against all collections. To query a specific collection, retrieve the collection list and resolve the target collection from its name — see the sample code below.
Delete a time-routed alias
Deleting the alias does not remove the collections it created. Delete both in the following order to avoid orphaned collections:
-
List all collections to identify the ones the alias created.
curl "http://solrhost:8983/solr/admin/collections?action=LIST"Collections created by
test_router_aliashave names starting withtest_router_alias(for example,test_router_alias_2020-03-04). -
Delete the alias.
curl "http://solrhost:8983/solr/admin/collections?action=DELETEALIAS&name=test_router_alias" -
Delete each collection.
curl "http://solrhost:8983/solr/admin/collections?action=DELETE&name=collection_name"
Find a collection by time range (LONG type)
When querying time series data, you may need to identify which collection covers a given time range rather than querying all collections. The following Java example uses CloudSolrClient and ClusterStateProvider to resolve the target collection from an alias and a LONG timestamp range.
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.impl.ClusterStateProvider;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.util.StrUtils;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
public class SolrDemo {
private static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE).appendPattern("[_HH[_mm[_ss]]]")
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.toFormatter(Locale.ROOT).withZone(ZoneOffset.UTC);
private static final String zkHost = "localhost:2181/solr";
private CloudSolrClient cloudSolrClient;
private ClusterStateProvider clusterStateProvider;
public SolrDemo() {
cloudSolrClient = new CloudSolrClient.Builder(
Collections.singletonList(zkHost), Optional.empty()).build();
cloudSolrClient.connect();
clusterStateProvider = cloudSolrClient.getClusterStateProvider();
}
public void close() throws Exception {
if (null != cloudSolrClient) {
cloudSolrClient.close();
}
}
private List<String> findCollection(String aliasName, long start, long end) {
List<String> collections = new ArrayList<>();
if (start > end) {
return collections;
}
// Query collections that fall within the time range [start, end].
if (clusterStateProvider.getState(aliasName) == null) {
// Retrieve all collections created by the alias.
// Example: test_router_alias_2020-03-04, test_router_alias_2020-02-26, ...
List<String> aliasedCollections = clusterStateProvider.resolveAlias(aliasName);
// Parse the date from each collection name.
// Example: 2020-03-04T00:00:00Z=test_router_alias_2020-03-04
List<Map.Entry<Instant, String>> collectionsInstant = new ArrayList<>(aliasedCollections.size());
for (String collectionName : aliasedCollections) {
String dateTimePart = collectionName.substring(aliasName.length() + 1);
Instant instant = DATE_TIME_FORMATTER.parse(dateTimePart, Instant::from);
collectionsInstant.add(new AbstractMap.SimpleImmutableEntry<>(instant, collectionName));
}
// Identify collections whose start time falls within the query range.
Instant startI = Instant.ofEpochMilli(start);
Instant endI = Instant.ofEpochMilli(end);
for (Map.Entry<Instant, String> entry : collectionsInstant) {
Instant colStartTime = entry.getKey();
if (! endI.isBefore(colStartTime)) {
collections.add(entry.getValue());
System.out.println("find collection: " + entry.getValue());
if (! startI.isBefore(colStartTime)) {
break;
}
}
}
} else {
collections.add(aliasName);
}
System.out.println("query " + collections);
return collections;
}
public void run() throws Exception {
try {
// Query the alias for documents in the range [2020-03-07, 2020-03-10].
long start = 1583538686312L;
long end = 1583797886000L;
String aliasName = "test_router_alias";
String collections = StrUtils.join(findCollection(aliasName, start, end), ',');
QueryResponse res = cloudSolrClient.query(collections, new SolrQuery("*:*"));
for (SolrDocument sd : res.getResults()) {
System.out.println(sd.get("id") + " " + sd.get("gmtCreate_l"));
}
} finally {
cloudSolrClient.close();
}
}
public static void main(String[] args) throws Exception {
SolrDemo solrDemo = new SolrDemo();
solrDemo.run();
solrDemo.close();
}
}