> ## Documentation Index
> Fetch the complete documentation index at: https://www.helius.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Solana DAS API ページネーション：効率的な大規模データセットのクエリ

> Solana DAS APIのページベースとキーセットページネーション。カーソルやレンジベースの戦略、並列クエリを使用して大規模データセットを効率的に反復。

## 概要

DAS API メソッドは 1 回の呼び出しで最大 1,000 レコードを返します。それ以上を取得するには、ページネーションを行います。これには複数回の呼び出しとデータのページをクロールすることが含まれます。Helius はページベースとキーセットページネーションの 2 つのメカニズムをサポートしています。

ページベースのページネーションは最も簡単に始められる方法です。キーセットページネーションは、大規模な（50万以上の）データセットを効率的にクエリするためのものです。

## 使用するタイミング

* **ページベース** — 静的ビュー、ダッシュボード、ほとんどの日常のクエリに最適。簡単で直感的。
* **キーセット（カーソルまたはレンジ）** — ページベースのクロールが遅くなる大規模データセット（全コレクション、50万以上の資産）。
* **並列キーセット** — アドレスレンジを分割して全コレクションをスキャンする最速のオプション。

## ソートオプション

`sortBy` フィールドを使用して、異なるフィールドで結果をソートできます。

| 値               | ソート基準              | 推奨? |
| --------------- | ------------------ | --- |
| `id`            | バイナリの資産 ID (デフォルト) | はい  |
| `created`       | 資産が作成された日付         | はい  |
| `recent_action` | 資産が最後に更新された日付      | いいえ |
| `none`          | ソートなし              | いいえ |

ソートを無効にすると最速の結果が得られますが、データは順序付けられていないため、ページネーション時に一貫性のない結果が得られる場合があります。

## ページベースのページネーション

ページ番号とページごとのアイテム数を指定します。次のページに進むには、ページ番号をインクリメントします。これ はほとんどのユースケースに対して簡単で直感的、かつ迅速です。

<Accordion title="例">
  ```javascript theme={"system"}
  const url = `https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY`

  const example = async () => {
      let page = 1;
      let items = [];
      while (true) {
          const response = await fetch(url, {
              method: 'POST',
              headers: {
                  'Content-Type': 'application/json',
              },
              body: JSON.stringify({
                  jsonrpc: '2.0',
                  id: 'my-id',
                  method: 'searchAssets',
                  params: {
                      grouping: ['collection', '5PA96eCFHJSFPY9SWFeRJUHrpoNF5XZL6RrE1JADXhxf'],
                      page: page,
                      limit: 1000,
                      sortBy: { sortBy: 'id', sortDirection: 'asc' },
                  },
              }),
          });
          const { result } = await response.json();
          if (result.items.length == 0) {
              console.log('No items remaining');
              break;
          } else {
              console.log(`Processing results from page ${page}`);
              items.push(...result.items);
              page += 1;
          }
      }
      console.log(`Got ${items.length} total items`);
  };
  example();
  ```
</Accordion>

ページを使用する場合、データベースは次のページに到達するまでのすべてのアイテムをクロールする必要があります。例えば、ページサイズが 1,000 のページ 100 が必要な場合、データベースは最初の 100 万レコードをトラバースしてからデータを返す必要があります。このため、ページベースのページネーションは大規模データセットには推奨されません。キーセットページネーションがその作業負荷に最適です。

## キーセットページネーション

ページはデータセットをフィルタリングする条件を指定することで定義されます。例えば、「ID > X かつ ID \< Y のすべての資産を取得する」といった具合です。各呼び出しで X または Y を変更することでデータセット全体をトラバースします。キーセットページネーションには次の 2 つの方法があります。

1. **カーソルベース** — 使用が簡単ですが柔軟性が低い。
2. **レンジベース** — より複雑ですが非常に柔軟。

キーセットページネーションは `id` でのソート時のみサポートされています。

### カーソルベース

ページネーションパラメータなしの DAS クエリはカーソルを返します。カーソルを DAS API に渡して中断したところから続行します。

<Accordion title="例">
  ```typescript theme={"system"}
  const url = `https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY`

  const example = async () => {
      let items = [];
      let cursor;
      while (true) {
          let params = {
              grouping: ['collection', '5PA96eCFHJSFPY9SWFeRJUHrpoNF5XZL6RrE1JADXhxf'],
              limit: 1000,
              sortBy: { sortBy: 'id', sortDirection: 'asc' },
          } as any;
          if (cursor != undefined) {
              params.cursor = cursor;
          }
          const response = await fetch(url, {
              method: 'POST',
              headers: {
                  'Content-Type': 'application/json',
              },
              body: JSON.stringify({
                  jsonrpc: '2.0',
                  id: 'my-id',
                  method: 'searchAssets',
                  params: params,
              }),
          });
          const { result } = await response.json();
          if (result.items.length == 0) {
              console.log('No items remaining');
              break;
          } else {
              console.log(`Processing results for cursor ${cursor}`);
              cursor = result.cursor;
              items.push(...result.items);
          }
      }
      console.log(`Got ${items.length} total items`);
  };
  example();
  ```
</Accordion>

執筆時点では、カーソルはレスポンスの最後の資産 ID ですが、カーソルデザインは柔軟であり、任意の文字列をサポートできます。

### レンジベース

レンジを指定してクエリするには、`before` および/または `after` を指定します。このクエリは本質的に「X より後、Y より前のすべての資産を取得する」というものです。各呼び出しで `before` または `after` パラメータを更新することでデータセットをトラバースします。

<Accordion title="例">
  ```javascript theme={"system"}
  const url = `https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY`

  const example = async () => {
      // Two NFTs from the Tensorian collection.
      // The "start" item has a lower asset ID (in binary) than the "end" item.
      // We will traverse in ascending order.
      let start = '6CeKtAYX5USSvPCQicwFsvN4jQSHNxQuFrX2bimWrNey';
      let end = 'CzTP4fUbdfgKzwE6T94hsYV7NWf1SzuCCsmJ6RP1xsDw';
      let sortDirection = 'asc';
      let after = start;
      let before = end;
      let items = [];

      while (true) {
          const response = await fetch(url, {
              method: 'POST',
              headers: {
                  'Content-Type': 'application/json',
              },
              body: JSON.stringify({
                  jsonrpc: '2.0',
                  id: 'my-id',
                  method: 'searchAssets',
                  params: {
                      grouping: ['collection', '5PA96eCFHJSFPY9SWFeRJUHrpoNF5XZL6RrE1JADXhxf'],
                      limit: 1000,
                      after: after,
                      before: before,
                      sortBy: { sortBy: 'id', sortDirection: sortDirection },
                  },
              }),
          });
          const { result } = await response.json();
          if (result.items.length == 0) {
              console.log('No items remaining');
              break;
          } else {
              console.log(`Processing results with (after: ${after}, before: ${before})`);
              after = result.items[result.items.length - 1].id;
              items.push(...result.items);
          }
      }
      console.log(`Got ${items.length} total items`);
  };
  example();
  ```
</Accordion>

## キーセットを使用した並列クエリ（上級者向け）

大規模データセット（例えば、圧縮された NFT コレクション全体）をクエリする上級者は、パフォーマンスのためにキーセットベースのページネーションを使用するべきです。次の例は、Solana アドレスレンジを分割し、`before`/`after` パラメータを使用して並列にクエリを行う方法を示しています。この方法は高速で効率的、安全です。

<Accordion title="例">
  以下の例では、Tensorian コレクション全体（約 10,000 レコード）をスキャンしています。Solana アドレス空間を 8 つのレンジに分割し、それらを同時にスキャンします。これは他の方法よりもはるかに高速です。

  ```typescript theme={"system"}
  import base58 from 'bs58';

  const url = `https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY`

  const main = async () => {
      let numParitions = 8;
      let partitons = partitionAddressRange(numParitions);
      let promises = [];
      for (const [i, partition] of partitons.entries()) {
          let [s, e] = partition;
          let start = bs58.encode(s);
          let end = bs58.encode(e);
          console.log(`Parition: ${i}, Start: ${start}, End: ${end}`);

          let promise: Promise<number> = new Promise(async (resolve, reject) => {
              let current = start;
              let totalForPartition = 0;
              while (true) {
                  const response = await fetch(url, {
                      method: 'POST',
                      headers: {
                          'Content-Type': 'application/json',
                      },
                      body: JSON.stringify({
                          jsonrpc: '2.0',
                          id: 'my-id',
                          method: 'searchAssets',
                          params: {
                              grouping: ['collection', '5PA96eCFHJSFPY9SWFeRJUHrpoNF5XZL6RrE1JADXhxf'],
                              limit: 1000,
                              after: current,
                              before: end,
                              sortBy: { sortBy: 'id', sortDirection: 'asc' },
                          },
                      }),
                  });
                  const { result } = await response.json();
                  totalForPartition += result.items.length;
                  console.log(`Found ${totalForPartition} total items in parition ${i}`);
                  if (result.items.length == 0) {
                      break;
                  } else {
                      current = result.items[result.items.length - 1].id;
                  }
              }
              resolve(totalForPartition);
          });
          promises.push(promise);
      }
      let results = await Promise.all(promises);
      let total = results.reduce((a, b) => a + b, 0);
      console.log(`Got ${total} total items`);
  };

  // Function to convert a BigInt to a byte array
  function bigIntToByteArray(bigInt: bigint): Uint8Array {
      const bytes = [];
      let remainder = bigInt;
      while (remainder > 0n) {
          // use 0n for bigint literal
          bytes.unshift(Number(remainder & 0xffn));
          remainder >>= 8n;
      }
      while (bytes.length < 32) bytes.unshift(0); // pad with zeros to get 32 bytes
      return new Uint8Array(bytes);
  }

  function partitionAddressRange(numPartitions: number) {
      let N = BigInt(numPartitions);

      // Largest and smallest Solana addresses in integer form.
      // Solana addresses are 32 byte arrays.
      const start = 0n;
      const end = 2n ** 256n - 1n;

      // Calculate the number of partitions and partition size
      const range = end - start;
      const partitionSize = range / N;

      // Calculate partition ranges
      const partitions: Uint8Array[][] = [];
      for (let i = 0n; i < N; i++) {
          const s = start + i * partitionSize;
          const e = i === N - 1n ? end : s + partitionSize;
          partitions.push([bigIntToByteArray(s), bigIntToByteArray(e)]);
      }

      return partitions;
  }

  main();
  ```
</Accordion>

## 次のステップ

<CardGroup cols={3}>
  <Card title="資産を検索" icon="magnifying-glass" href="/ja/das/search">
    所有者、コレクション、tokenType で資産をフィルタします。
  </Card>

  <Card title="資産 (NFT) を取得" icon="image" href="/ja/das/get-nfts">
    NFT、コレクション、エディション、プルーフを取得します。
  </Card>

  <Card title="DAS API リファレンス" icon="code" href="/ja/api-reference/das">
    すべての DAS メソッドのフルスキーマ。
  </Card>
</CardGroup>
