このトピックでは、シャーディング機能に適したシナリオと、その使用方法について説明します。
背景情報
ビジネスロジックでは、テーブル A を使用してビジネスデータを格納します。テーブル B を使用してデータを格納するには、構成を変更します。
シャーディング
ほとんどのビジネスシナリオでは、前の週に生成されたデータのみが頻繁にアクセスされます。毎週テーブルを作成して最新のデータを格納できます。このアプローチにより、ホットデータを効率的にクエリできます。ただし、手動でテーブルを作成および削除する必要があるため、ビジネスロジックの複雑さが増します。
シナリオ
時系列データの管理
ビジネスデータが時間に敏感な場合、時間に基づいて複数のインデックスを作成できます。これにより、単一のインデックスのサイズが縮小され、クエリのパフォーマンスが向上します。このプロセス中に、手動でインデックスを作成または削除する必要はありません。
インデックスの再構築
既存のインデックスベースのデータクエリに影響を与えることなく、インデックスを再構築できます。インデックスが再構築されると、新しいインデックスがデータのクエリに使用されます。このプロセス中に、既存のコードを変更する必要はありません。
既存のコレクションのエイリアスの作成
curl "http://solrhost:8983/solr/admin/collections?action=CREATEALIAS&name=your_alias_name&collections=your_collection_name_A" 上記の URL は、your_collection_name_A コレクションを指す your_allias_name という名前のエイリアスを作成することを示します。ビジネスロジックでは、your_alias_name のみにアクセスするように設定でき、カーネルはリクエストを実際のコレクションに自動的に転送します。
コレクション名を your_collection_name_B に変更するには、コマンドを実行してエイリアスを変更します。
curl "http://solrhost:8983/solr/admin/collections?
action=ALIASPROP&name=your_alias_name&collections=your_collection_name_B" ビジネスコードを変更することなく、新しいコレクションにアクセスできます。
自動テーブルシャーディング
LindormSearch は、時間フィールドの値に基づいてコレクションを自動的に作成できます。これにより、ビジネスロジックを簡素化できます。次の例は、毎週コレクションを作成し、期限切れのコレクションを自動的に削除するようにシステムを構成する方法を示しています。
curl "http://solrhost:8983/solr/admin/collections?action=CREATEALIAS&name=test_router_alias&router.start=NOW-30DAYS/DAY&router.autoDeleteAge=/DAY-90DAYS&router.field=your_timestamp_l&router.name=time&router.interval=%2B7DAY&router.maxFutureMs=8640000000&create-collection.collection.configName=_indexer_default&create-collection.numShards=2" パラメーター | 値の例 | 説明 |
router.start | NOW-30DAYS/DAY | 最初のコレクションの時間範囲の開始。この例では、NOW-30DAYS/DAY は、開始時刻が現在の時刻の 30 日前であることを示します。 |
router.interval | +7DAY | 新しいコレクションが作成される間隔。この例では、7 日ごとに新しいコレクションが作成されます。 |
router.autoDeleteAge | /DAY-90DAYS | コレクションが自動的に削除される前に保持される期間。この例の値は、システムが 90 日間保存されたコレクションを自動的に削除することを示します。このパラメーターの値は、router.start パラメーターの値より大きい必要があります。 |
router.field | your_timestamp_l | コレクションの作成に使用される時間フィールド。デフォルトでは、指定された値を持つこのフィールドは、ビジネスデータに含まれている必要があります。たとえば、値を System.currentTimeMillis() に設定できます。この値は、現在のシステムのタイムスタンプです。 |
router.maxFutureMs | 8640000000 | your_date_dt フィールドの値と現在の時刻との間で許容される最大差。このパラメーターは、指定された時間範囲内に生成されたデータのみがコレクションに書き込まれるようにします。この例では、このパラメーターの値は、前の 100 日間または次の 100 日間に生成されたデータのみがコレクションに書き込めることを示します。 |
collection.collection.configName | _indexer_default | コレクションが依存する構成セット。このパラメーターを構成セットの名前に設定できます。詳細については、「構成セットの更新」をご参照ください。 |
create-collection.numShards | 2 | コレクション用に作成されるシャードの数。デフォルト値: 2。 |
上記のビジネスロジックは次のことを意味します: 30 日前 (今日が 3 月 7 日であると仮定) から、your_timestamp_l フィールドを使用して 7 日ごとにインデックスを作成します。フィールド値は現在の時刻から 100 日以内でなければならず、システムは 90 日前に期限切れになったインデックスを定期的に削除します。
次の図に結果を示します:

ビジネスデータには時間フィールドが含まれている必要があります。時間フィールドのデータの型は DATE または LONG にすることができます。
デフォルトでは、すべてのコレクションがクエリされます。クエリするコレクションを指定できます。これを行うには、指定された URL で curl コマンドを実行するか、特定の API 操作を呼び出してすべてのコレクションを取得します。次に、コレクションから時間フィールドの値を取得し、クエリするコレクションを指定できます。詳細については、「次のサンプルコード」をご参照ください。
エイリアスの削除
共通のエイリアスを削除するには、次のコマンドを実行します:
curl "http://solrhost:8983/solr/admin/collections?action=DELETEALIAS&name=your_alias_name" 自動テーブルシャーディングを持つエイリアスを削除するには、関連付けられたコレクションもアクティブに削除する必要があります。
エイリアスに関連付けられたコレクションのリストを取得します。
curl "http://solrhost:8983/solr/admin/collections?action=LIST"test_router_aliasで始まる名前のコレクションはすべて、このエイリアスに関連付けられています。エイリアスを削除します。
curl "http://solrhost:8983/solr/admin/collections?action=DELETEALIAS&name=test_router_alias"すべてのコレクションを削除します。
curl "http://solrhost:8983/solr/admin/collections?action=DELETE&name=collection_name"
リファレンス
CREATEALIAS: CREATEALIAS
LIST: LIST
LONG 型の時間を使用してクエリする方法
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;
}
// [start, end] に基づいて適切なコレクションを検索します
if (clusterStateProvider.getState(aliasName) == null) {
// 現在の aliasName に対応するすべてのコレクションリストを取得します
// test_router_alias_2020-03-04, test_router_alias_2020-02-26, test_router_alias_2020-02-19, test_router_alias_2020-02-12, test_router_alias_2020-02-05
List<String> aliasedCollections = clusterStateProvider.resolveAlias(aliasName);
// コレクション名から日付と時刻を抽出します
// 2020-03-04T00:00:00Z=test_router_alias_2020-03-04,
// 2020-02-26T00:00:00Z=test_router_alias_2020-02-26,
// 2020-02-19T00:00:00Z=test_router_alias_2020-02-19,
// 2020-02-12T00:00:00Z=test_router_alias_2020-02-12,
// 2020-02-05T00:00:00Z=test_router_alias_2020-02-05
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));
}
// クエリ時間に基づいて適切なコレクションを検索します
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 {
// [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();
}
}