メインコンテンツへスキップ

Recent search エンドポイントのページネーション

はじめに

検索クエリは、通常 1 回の API レスポンスで返却できる数より多くの投稿に一致します。その場合、データは「ページ」の連なりとして返されます。ページネーションとは、データセット全体を取得するために、すべてのページを順番にリクエストする方法を指します。 以下は、recent search のページネーションに関する基本事項です。
  • recent search エンドポイントは、クエリに対して少なくとも 1 ページのレスポンスを返し、追加のページが利用可能な場合は JSON レスポンス内に next_token を含めます。一致する投稿をすべて受信するには、レスポンスにトークンが含まれなくなるまで、この処理を繰り返すことができます。
  • next_token は有効期限切れになりません。同じ next_token 値を使って複数回リクエストしても、リクエストを送信したタイミングに関係なく、同じ結果が返されます。
  • 投稿は UTC タイムゾーンで、新しいものから古いものへの逆時系列で配信されます。これは個々のページ内でも、複数ページをまたいでも同様です。 
    • 最初のレスポンス内の最初の投稿は、クエリに一致する中で最も新しいものです。
    • 最後のレスポンス内の最後の投稿は、クエリに一致する中で最も古いものです。
  • max_results リクエストパラメータを使うと、1 レスポンスあたりに返される投稿数を設定できます。デフォルトは 10 件の投稿で、最大値は 100 件です。 
  • すべてのページネーション実装では、レスポンスペイロードから next_token をパースし、それを「次のページ」の検索リクエストに含める必要があります。これらの「次のページ」リクエストをどのように構築するかについては、以下の詳細を参照してください。  
recent search エンドポイントは、2 つの基本的な利用パターンをサポートするように設計されています。
  • Get historical - 関心のある期間に投稿された、一致する投稿をリクエストします。これは通常、履歴調査を支援するための一度きりのリクエストです。検索リクエストは start_time と end_time のリクエストパラメータに基づいて発行できます。recent search エンドポイントは、クエリに一致する中で最も新しい投稿から始まり、逆時系列で投稿を返します。 
  • Polling - 最後に受信した投稿以降に投稿された、一致する投稿をリクエストします。これらのユースケースは、ほぼリアルタイムな利用を想定しており、関心のある新しい投稿を「リッスン」するための頻繁なリクエストが特徴です。recent search エンドポイントは、「polling」パターンをサポートするために since_id リクエストパラメータを提供します。投稿 ID によるナビゲーションを容易にするために、until_id リクエストパラメータも利用可能です。  
次に、履歴モードについて説明します。これは recent search エンドポイントのデフォルトモードであり、ページネーションの基本を示すものです。その後、ポーリングのユースケース例について説明します。ポーリングによってページネーションが発生する場合、検索リクエストを管理する追加の手順が必要になります。  

履歴データの取得

このセクションでは、start_time と end_time リクエストパラメータを使用して、関心のある期間 (現在は直近 7 日間に制限) から投稿を取得する方法について説明します。履歴データのリクエストは、通常、調査や分析を目的とした一度きりのリクエストです。  特定の期間のデータをリクエストすることは、recent search エンドポイントのデフォルト動作です。検索リクエストで start_time、end_time、または since_id リクエストパラメータが指定されていない場合、end_time は「現在」 (実際にはクエリ実行時刻の 30 秒前) に、start_time は 7 日前にデフォルト設定されます。 エンドポイントは、もっとも新しい投稿から開始して、逆時系列で最初の「ページ」の投稿を返します。レスポンスの JSON ペイロードには、追加のデータページが存在する場合、next_token も含まれます。ページ数に関係なく、一致する投稿の完全なセットを収集するには、next_token が返されなくなるまでリクエストを繰り返します。  例えば、直近 1 週間の間に snow というキーワードを含む投稿に対する最初のリクエストは次のようになります。 https://api.x.com/2/tweets/search/recent?query=snow このレスポンスには、もっとも最近の 10 件の投稿とともに、JSON レスポンス内の次の「meta」属性が含まれます。
"meta": {
        "newest_id": "1204860593741553664",
        "oldest_id": "1204860580630278147",
        "next_token": "b26v89c19zqg8o3fobd8v73egzbdt3qao235oql",
        "result_count": 10
    }
次の 10 件の投稿を取得するには、この next_token を元のリクエストに追加します。リクエストは次のようになります。 https://api.x.com/2/tweets/search/recent?query=snow&next_token=b26v89c19zqg8o3fobd8v73egzbdt3qao235oql next_token を探して後続のリクエストに含める処理は、すべての投稿 (または所定の件数の投稿) が収集されるまで、あるいは指定した回数のリクエストを行うまで繰り返すことができます。データの完全性 (クエリに一致するすべてを収集すること) がユースケースで重要な場合は、単純な “request.next_token が null になるまで繰り返す” という設計で十分です。

ポーリングおよびリスニングのユースケース

このセクションでは、since_id リクエストパラメータを指定して recent search エンドポイントをポーリングすることで、最近の投稿を取得する方法について説明します。  ポーリングのユースケースでは、「関心のある新しい投稿はあるか?」というクエリを継続的かつ高頻度で行います。時間ベースでリクエストを行う履歴系ユースケースとは異なり、ポーリングのユースケースでは通常、投稿 ID を基準にリクエストを行います。 ポーリングパターンの要点は、すべての新しい投稿には unique ID があり、X プラットフォームから一般的に昇順で「発行」されるという点です。ある投稿の ID が別の投稿より小さい場合、それは前者の方が先に投稿されたことを意味します。 recent search エンドポイントは、投稿 ID に基づいて投稿アーカイブをナビゲートすることをサポートします。エンドポイントからのレスポンスには、oldest_id および newest_id の投稿 ID が含まれます。ポーリングモードでは、これまでに受信した中で最大/最新の ID を since_id に設定してリクエストを行います。  例えば、雪に関する新しい投稿を 5 分ごとに検索していて、最後に受信した投稿の投稿 ID が 10000 だったとします。次にポーリングを行うタイミングでは、リクエストは次のようになります。 https://api.x.com/2/tweets/search/recent?query=snow&since_id=10000 次に、前回のリクエスト以降に 7 件の投稿が行われたとします。これらはすべて単一のデータ「ページ」に収まるため、next_token は存在しません。レスポンスには、最新 (最も新しい) の投稿の投稿 ID が含まれます。
"meta": {
        "newest_id": "12000",
        "oldest_id": "10005",
        "result_count": 7
    }
次のポーリングクエリを行うには、この newest_id の値を使って、次の since_id パラメータを設定します。 https://api.x.com/2/tweets/search/recent?query=snow&since_id=12000 さらに取得可能なデータがあり、next トークンが返される場合でも、結果の最初のページに含まれる newest_id の値だけを使えば十分です。各ページのデータには newest_id と oldest_id の値が含まれますが、次に定期実行されるポーリングリクエストで必要なのは、最初のページで提供される値だけです。そのため、ポーリング設計を実装している場合や、ID の範囲で投稿を検索している場合、ページネーションロジックは少しだけ複雑になります。  ここで、さらに 18 件の一致する投稿があるとします。エンドポイントは、この 5 分間のデータについて、次のページのデータをリクエストするための next_token を含む、1 ページ分の完全な初回レスポンスを返します。また、次の 5 分後のポーリング間隔で必要となる最新の投稿 ID も含まれます。
"meta": {
        "newest_id": "13800",
        "oldest_id": "12500",
        "next_token": "fnsih9chihsnkjbvkjbsc",
        "result_count": 10
    }
この5分間の期間に一致するすべてのデータを収集するには、前回のリクエストと同じ since_id の値を指定したうえで、next_token を次のリクエストに渡してください。 https://api.x.com/2/tweets/search/recent?query=snow&since_id=12000&next_token=fnsih9chihsnkjbvkjbsc
"meta": {
        "newest_id": "12300",
        "oldest_id": "12010",
        "result_count": 8
    }
この 2 回目のレスポンスでは残りの 8 件の投稿が返され、next_token は含まれません。newest_id の値 (12300) は更新せず、代わりに次回の since_id を指定したリクエストは、最初のレスポンスの newest_id の値に基づいて行う点に注意してください。 https://api.x.com/2/tweets/search/recent?query=snow&since_id=13800