このトピックでは、シャーディング機能が適しているシナリオについて説明します。また、この機能の使用方法についても説明します。
背景情報
ビジネスロジックでは、テーブル A を使用してビジネスデータを格納します。テーブル B を使用してデータを格納する必要がある場合は、構成を変更できます。
シャーディング
ほとんどのビジネスシナリオでは、前の週に生成されたデータのみに頻繁にアクセスします。毎週テーブルを作成して最新のデータを格納できます。このようにして、ホットデータを効率的にクエリできます。ただし、テーブルを手動で作成および削除する必要があります。これは、ビジネスロジックの複雑さを増大させます。
シナリオ
時系列データを管理する
ビジネスデータが時間に依存する場合は、時間に基づいて複数のインデックスを作成できます。これにより、単一インデックスのサイズが縮小され、クエリのパフォーマンスが向上します。このプロセス中に、インデックスを手動で作成または削除する必要はありません。
インデックスを再構築する
インデックスを再構築できます。再構築操作は、既存のインデックスベースのデータクエリには影響しません。インデックスが再構築されると、新しいインデックスを使用してデータがクエリされます。このプロセス中に、既存のコードを変更する必要はありません。
既存のコレクションのエイリアスを作成する
curl "http://solrhost:8983/solr/admin/collections?action=CREATEALIAS&name=your_alias_name&collections=your_collection_name_A"
上記の curl コマンドを実行して、your_alias_name という名前のエイリアスを作成します。エイリアスはコレクション your_collection_name_A を指します。ビジネスロジックで your_alias_name エイリアスを指定できます。その後、カーネルはクエリ要求をコレクションに転送します。コレクションの名前を your_collection_name_B に変更する場合は、curl コマンドを実行してエイリアスを変更します。
エイリアスを変更する
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。 |
上記の curl コマンドを実行すると、your_timestamp_l フィールドの値に基づいて 7 日ごとにコレクションが作成されます。最初のコレクションの時間範囲の開始は、現在時刻の 30 日前です。 your_timestamp_l フィールドの値と現在時刻の差は 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"
参照
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();
}
}