-
Notifications
You must be signed in to change notification settings - Fork 20
Add DataLoader support for Crawl to solve N+1 problem #346
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Add optional batch processing mechanism that reduces resource requests during Crawl traversal. - Add `batch` parameter to #[Link] annotation to specify BatchResolver - Add BatchResolverInterface for implementing custom batch logic - Add Requests class with helper methods (getQueryParam, mapResults) - Add Results class for URI-keyed result mapping - Add BatchResolverFactoryInterface for DI integration - Modify Linker to process batch-enabled links efficiently 100% backward compatible - existing code works without changes. Batch processing is opt-in via the new `batch` parameter.
Rename BatchResolver to DataLoader following GraphQL's DataLoader pattern: - src/Batch/ → src/DataLoader/ - BatchResolverInterface → DataLoaderInterface - BatchResolverFactory → DataLoaderFactory - LikeBatchResolver → LikeDataLoader The naming better reflects the pattern's purpose and origin.
- Add DataLoaderModule to src/Module for easy installation - Add edge case tests for Requests class (empty URIs, missing keys) - Add additional Linker tests (multiple invokes, empty comments) - Add demo for DataLoader usage pattern - Update Link annotation property to use dataLoader parameter
- Apply constructor property promotion in Requests class - Use early exit pattern for better code readability - Add psalm-suppress annotations for intentional mixed types - Fix fully qualified class name reference in Types.php - Format single-element arrays on single lines
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the 概要DataLoader機能を導入し、Link注釈に 変更内容
シーケンス図sequenceDiagram
participant Linker
participant DataLoader
participant DI as DI Container
participant LikeDataLoader
participant DB as Data Store
Linker->>Linker: annotationCrawl: collect Link annotations
Linker->>Linker: filter: Link with dataLoader specified
Linker->>DataLoader: load(annotations, link, bodyList)
DataLoader->>DataLoader: extractKeysFromTemplate(href)
DataLoader->>DataLoader: build queries from bodyList items
DataLoader->>DI: getDataLoader(dataLoader class)
DI->>LikeDataLoader: instantiate LikeDataLoader
DataLoader->>LikeDataLoader: __invoke(queries)
LikeDataLoader->>DB: bulk fetch likes by comment_id
DB-->>LikeDataLoader: rows (aggregated)
LikeDataLoader-->>DataLoader: return rows
DataLoader->>DataLoader: buildGroupKey(row, extracted keys)
DataLoader->>DataLoader: group results by keys
DataLoader->>DataLoader: distribute grouped results to bodyList
DataLoader-->>Linker: updated bodyList
Linker->>Linker: continue crawl with populated relations
推定コードレビュー負荷🎯 4 (Complex) | ⏱️ ~45 分 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## 1.x #346 +/- ##
===========================================
Coverage 100.00% 100.00%
- Complexity 541 575 +34
===========================================
Files 84 86 +2
Lines 1370 1451 +81
===========================================
+ Hits 1370 1451 +81 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
- Extract DataLoader processing logic into separate DataLoaderProcessor class - Linker now delegates to DataLoaderProcessor instead of handling DataLoader logic directly - Reduces Linker's class complexity below PHPMD threshold of 50 - Add DataLoaderProcessorTest for 100% coverage of edge cases
041f51d to
ce8d000
Compare
- Remove DataLoaderFactory and DataLoaderFactoryInterface - DataLoaderProcessor now uses InjectorInterface directly - Simplifies the architecture by eliminating unnecessary abstraction
- Remove Requests and Results classes
- Simplify DataLoaderInterface to __invoke(array $queries): array
- Auto-infer key from URI template (no dataLoaderKey needed)
- Support both URI formats: {?var} and param={var}
- Add RowMustContainKeyInDataLoaderException
Document that $queries is passed as associative arrays (not just values) to support multiple key parameters in URI templates.
- Rename DataLoaderProcessor class to DataLoader - Rename process() method to load() - Add domain types to Types.php (DataLoaderQuery, DataLoaderRow, etc.) - Update DataLoaderInterface to use imported types
- Remove separate DataLoaderModule - DataLoader is now included by default in ResourceClientModule - Update demo to use simplified module setup
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
tests/DataLoader/LinkerDataLoaderTest.php (1)
149-167: 空のコメントリストに対するエッジケースのテスト。Line 166 で空のクエリリストでも DataLoader が1回呼び出されることを確認していますが、これは意図した動作でしょうか?空のクエリでは DataLoader を呼び出さない最適化も検討できます。
src/DataLoader/DataLoader.php (1)
154-172: 冗長な assert を削除できます。Line 159 の
assert(is_string($queryString))は、Line 155 で既にis_string($queryString)をチェックしているため不要です。♻️ 修正案
if (! is_string($queryString) || ! str_contains($queryString, '=')) { return []; } - assert(is_string($queryString)); parse_str($queryString, $params);demo/4.link-crawl-dataloader.php (1)
33-71: LikeDataLoader の実装は DataLoaderInterface の使用法を適切に示しています。Based on learnings, インターフェースは
public function __invoke(array $queries): arrayを使用しており、この実装はその設計に従っています。Line 65 の
array_mergeをループ内で使用している点は、デモとしては問題ありませんが、大量データでは...スプレッド演算子の方がパフォーマンスが良いです。♻️ パフォーマンス改善案(オプション)
// 2. Bulk fetch: SELECT * FROM likes WHERE comment_id IN (...) - $rows = []; - foreach ($commentIds as $commentId) { - $likes = self::$data[(int) $commentId] ?? []; - $rows = array_merge($rows, $likes); - } + $rows = array_merge( + ...array_map( + static fn ($id) => self::$data[(int) $id] ?? [], + $commentIds, + ), + );
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
demo/4.link-crawl-dataloader.phpsrc/Annotation/Link.phpsrc/DataLoader/DataLoader.phpsrc/DataLoader/DataLoaderInterface.phpsrc/Exception/RowMustContainKeyInDataLoaderException.phpsrc/Linker.phpsrc/Module/ResourceClientModule.phpsrc/Types.phptests/DataLoader/DataLoaderTest.phptests/DataLoader/LinkerDataLoaderTest.phptests/Fake/FakeVendor/Sandbox/DataLoader/LikeDataLoader.phptests/Fake/FakeVendor/Sandbox/Resource/App/Batch/Article.phptests/Fake/FakeVendor/Sandbox/Resource/App/Batch/Comment.phptests/Fake/FakeVendor/Sandbox/Resource/App/Batch/Like.php
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: koriym
Repo: bearsunday/BEAR.Resource PR: 0
File: :0-0
Timestamp: 2026-01-09T18:36:49.781Z
Learning: The Link annotation parameter for DataLoader in BEAR.Resource is `dataLoader` (not `batch`). Example: `#[Link(crawl: 'tree', rel: 'like', href: 'app://self/like{?comment_id}', dataLoader: LikeDataLoader::class)]`
Learnt from: koriym
Repo: bearsunday/BEAR.Resource PR: 0
File: :0-0
Timestamp: 2026-01-09T15:46:03.544Z
Learning: The DataLoader pattern in BEAR.Resource is inspired by Facebook's DataLoader and intentionally keeps the framework interface simple (Requests → Results). Advanced concerns like batching limits, error recovery strategies, and custom mapping logic are the DataLoader implementer's responsibility, not the framework's.
Learnt from: koriym
Repo: bearsunday/BEAR.Resource PR: 0
File: :0-0
Timestamp: 2026-01-09T18:36:49.781Z
Learning: In BEAR.Resource's DataLoader implementation, the interface was finalized to use plain PHP arrays: `public function __invoke(array $queries): array` where both parameters and return values are `list<array<string, mixed>>`. This replaced the earlier Requests/Results object approach for maximum simplicity.
📚 Learning: 2026-01-09T15:46:03.544Z
Learnt from: koriym
Repo: bearsunday/BEAR.Resource PR: 0
File: :0-0
Timestamp: 2026-01-09T15:46:03.544Z
Learning: DataLoaderFactory in BEAR.Resource validates DataLoader instances via assert($instance instanceof DataLoaderInterface).
Applied to files:
tests/DataLoader/DataLoaderTest.phpsrc/Linker.phpsrc/Types.phptests/DataLoader/LinkerDataLoaderTest.phpsrc/DataLoader/DataLoader.phptests/Fake/FakeVendor/Sandbox/DataLoader/LikeDataLoader.phpsrc/Module/ResourceClientModule.phpsrc/Exception/RowMustContainKeyInDataLoaderException.phpsrc/DataLoader/DataLoaderInterface.phpsrc/Annotation/Link.php
📚 Learning: 2026-01-09T18:36:49.781Z
Learnt from: koriym
Repo: bearsunday/BEAR.Resource PR: 0
File: :0-0
Timestamp: 2026-01-09T18:36:49.781Z
Learning: The Link annotation parameter for DataLoader in BEAR.Resource is `dataLoader` (not `batch`). Example: `#[Link(crawl: 'tree', rel: 'like', href: 'app://self/like{?comment_id}', dataLoader: LikeDataLoader::class)]`
Applied to files:
tests/DataLoader/DataLoaderTest.phpsrc/Linker.phpsrc/Types.phptests/DataLoader/LinkerDataLoaderTest.phpsrc/DataLoader/DataLoader.phptests/Fake/FakeVendor/Sandbox/DataLoader/LikeDataLoader.phpdemo/4.link-crawl-dataloader.phpsrc/Module/ResourceClientModule.phptests/Fake/FakeVendor/Sandbox/Resource/App/Batch/Comment.phpsrc/Annotation/Link.php
📚 Learning: 2026-01-09T18:36:49.781Z
Learnt from: koriym
Repo: bearsunday/BEAR.Resource PR: 0
File: :0-0
Timestamp: 2026-01-09T18:36:49.781Z
Learning: In BEAR.Resource's DataLoader implementation, the interface was finalized to use plain PHP arrays: `public function __invoke(array $queries): array` where both parameters and return values are `list<array<string, mixed>>`. This replaced the earlier Requests/Results object approach for maximum simplicity.
Applied to files:
tests/DataLoader/DataLoaderTest.phpsrc/Linker.phpsrc/Types.phpsrc/DataLoader/DataLoader.phptests/Fake/FakeVendor/Sandbox/DataLoader/LikeDataLoader.phpdemo/4.link-crawl-dataloader.phpsrc/Module/ResourceClientModule.phpsrc/DataLoader/DataLoaderInterface.phpsrc/Annotation/Link.php
📚 Learning: 2026-01-09T18:36:49.781Z
Learnt from: koriym
Repo: bearsunday/BEAR.Resource PR: 0
File: :0-0
Timestamp: 2026-01-09T18:36:49.781Z
Learning: BEAR.Resource's DataLoader auto-infers key columns from URI templates in the Link annotation. Supported formats: `{?comment_id}` extracts key `comment_id`, and `comment_id={id}` also identifies `comment_id` as the key. This eliminates the need for manual key specification.
Applied to files:
tests/DataLoader/DataLoaderTest.phpsrc/Linker.php
📚 Learning: 2026-01-09T15:46:03.544Z
Learnt from: koriym
Repo: bearsunday/BEAR.Resource PR: 0
File: :0-0
Timestamp: 2026-01-09T15:46:03.544Z
Learning: The DataLoader pattern in BEAR.Resource is inspired by Facebook's DataLoader and intentionally keeps the framework interface simple (Requests → Results). Advanced concerns like batching limits, error recovery strategies, and custom mapping logic are the DataLoader implementer's responsibility, not the framework's.
Applied to files:
src/Linker.phpsrc/Types.phpsrc/DataLoader/DataLoader.phptests/Fake/FakeVendor/Sandbox/DataLoader/LikeDataLoader.phpdemo/4.link-crawl-dataloader.phpsrc/Module/ResourceClientModule.phpsrc/DataLoader/DataLoaderInterface.phpsrc/Annotation/Link.php
📚 Learning: 2025-10-28T00:42:34.230Z
Learnt from: koriym
Repo: bearsunday/BEAR.Resource PR: 337
File: src/HttpResourceObject.php:18-24
Timestamp: 2025-10-28T00:42:34.230Z
Learning: In the BEAR.Resource codebase, type names like `Headers`, `HttpBody`, `Query`, `Body`, etc., are Psalm type aliases (domain types) defined in `src/Types.php` and imported via `psalm-import-type`. These are documentation-level types for static analysis that resolve to `array` at runtime. Method signatures correctly use `array` type hints while docblocks use the specific type aliases for Psalm validation.
Applied to files:
src/Types.php
🧬 Code graph analysis (8)
tests/DataLoader/DataLoaderTest.php (3)
src/DataLoader/DataLoader.php (2)
DataLoader(34-243)load(54-67)src/Exception/RowMustContainKeyInDataLoaderException.php (1)
RowMustContainKeyInDataLoaderException(12-18)src/LinkType.php (1)
LinkType(7-18)
src/Linker.php (1)
src/DataLoader/DataLoader.php (2)
DataLoader(34-243)load(54-67)
tests/Fake/FakeVendor/Sandbox/Resource/App/Batch/Like.php (2)
src/Resource.php (1)
Resource(23-178)src/ResourceObject.php (1)
ResourceObject(38-287)
src/DataLoader/DataLoader.php (5)
src/Exception/RowMustContainKeyInDataLoaderException.php (1)
RowMustContainKeyInDataLoaderException(12-18)src/LinkType.php (1)
LinkType(7-18)src-files/uri_template.php (1)
uri_template(15-24)src/Linker.php (2)
__construct(43-48)crawl(206-233)src/ResourceInterface.php (1)
uri(36-36)
tests/Fake/FakeVendor/Sandbox/DataLoader/LikeDataLoader.php (3)
src/DataLoader/DataLoader.php (1)
DataLoader(34-243)demo/4.link-crawl-dataloader.php (3)
Like(118-128)LikeDataLoader(33-71)__invoke(51-70)src/DataLoader/DataLoaderInterface.php (1)
__invoke(40-40)
src/Module/ResourceClientModule.php (1)
src/DataLoader/DataLoader.php (1)
DataLoader(34-243)
tests/Fake/FakeVendor/Sandbox/Resource/App/Batch/Article.php (3)
tests/Fake/FakeVendor/Sandbox/Resource/App/Batch/Comment.php (1)
Link(25-31)src/Linker.php (1)
crawl(206-233)tests/Fake/FakeVendor/Sandbox/Resource/App/Batch/Like.php (1)
onGet(30-35)
src/Annotation/Link.php (2)
src/DataLoader/DataLoader.php (1)
DataLoader(34-243)src/Linker.php (2)
__construct(43-48)crawl(206-233)
🔇 Additional comments (26)
src/DataLoader/DataLoaderInterface.php (1)
1-41: インターフェース設計が優れていますDataLoaderInterfaceの設計は明確でシンプルです。以下の点が特に良好です:
- プレーンなPHP配列を使用し、フレームワークの複雑さを最小限に抑えている
- 単一キーと複数キーの両方のユースケースについて、実用的な例を含む包括的なドキュメント
- Psalm型アノテーションによる型安全性の確保
Based on learnings, この実装はFacebookのDataLoaderパターンに倣い、フレームワークインターフェースをシンプルに保つという意図に沿っています。
src/Module/ResourceClientModule.php (1)
9-9: DataLoaderのDIバインディングが適切に追加されていますDataLoader::classのバインディングにより、Linkerなどのコンポーネントでの注入が可能になります。後方互換性を保ちながら、新機能を有効にする適切な統合ポイントです。
Also applies to: 102-102
tests/Fake/FakeVendor/Sandbox/Resource/App/Batch/Like.php (1)
9-36: テストフィクスチャが適切に構成されていますこのLikeリソースは、DataLoaderのテストに必要なデータ構造を提供しています:
- comment_idでキー付けされた静的データは、バッチ処理のテストシナリオをサポート
- デフォルトパラメータを持つonGetメソッドにより、柔軟なテストが可能
- 詳細なPsalm型アノテーションにより型安全性を確保
src/Exception/RowMustContainKeyInDataLoaderException.php (1)
1-18: 例外クラスが明確で焦点が絞られていますRowMustContainKeyInDataLoaderExceptionの実装は適切です:
- 検証失敗時に開発者にとって明確で実用的なエラーメッセージを提供
- finalクラスとして定義され、フレームワークのExceptionInterfaceを実装
- DataLoaderの契約違反を適切に表現
src/Linker.php (4)
46-46: DataLoaderの注入が後方互換性を維持していますコンストラクタパラメータとして
DataLoader|null $dataLoader = nullを追加することで、以下を実現:
- nullableでデフォルト値nullにより、既存のコードへの影響なし
- 新しいDataLoader機能はオプトイン方式で利用可能
- 適切な依存性注入による疎結合
175-177: DataLoaderの事前処理が正しく配置されていますannotationCrawlメソッド内で、DataLoader対応リンクを手動クロールループの前に処理することで、N+1問題の解決を実現:
dataLoader?->load()により、バッチ処理可能なすべてのリンクを一度に処理- null安全演算子の使用により、DataLoaderが利用できない場合も安全に動作
- 既存の手動クロールロジックは、非DataLoaderリンク用に保持
Based on learnings, この設計により、単一リクエストでバッチ処理し、データサイズに依存しないクエリ数を達成します。
213-216: スキップロジックが重複処理を適切に防止していますcrawlメソッドのガード条件により、DataLoaderで既に処理されたリンクの再処理を回避:
- 両方の条件(
$annotation->dataLoader !== nullAND$this->dataLoader !== null)をチェック- DataLoaderが利用可能で、かつアノテーションでDataLoaderが指定されている場合のみスキップ
- 手動クロールとDataLoaderバッチ処理の明確な責任分離
189-189: Psalm抑制の追加について
InvalidArrayAccessの抑制が追加されていますが、これは妥当な対応です:
- Line 174で
$bodyList = $isList ? (array) $current->body : [$current->body];により、!$isListの場合は常に$bodyList[0]が存在- Psalmは配列が非空であることを静的に検証できないため、抑制が必要
- 実行時の安全性はコードロジックにより保証されている
tests/Fake/FakeVendor/Sandbox/Resource/App/Batch/Article.php (1)
10-22: LGTM!テストリソースの実装が適切ですArticleリソースの実装は明確でシンプルです。Link annotationを使用してCommentリソースへのクロール関係を正しく定義しており、DataLoader統合のテストシナリオに適しています。
tests/Fake/FakeVendor/Sandbox/DataLoader/LikeDataLoader.php (1)
13-39: LGTM!DataLoaderの実装がインターフェースに適合していますLikeDataLoaderの実装は正しく、テスト目的に適しています:
array_columnを使用してcomment_idを効率的に抽出- バルクフェッチのシミュレーションが適切
$callCountとreset()メソッドによりテストでの呼び出し回数の検証が可能Based on learnings, DataLoaderインターフェースの単純な配列ベースの契約(
array $queries→array)に正しく準拠しています。tests/Fake/FakeVendor/Sandbox/Resource/App/Batch/Comment.php (1)
11-32: LGTM!DataLoaderを使用したLink annotationが正しく実装されていますCommentリソースは、DataLoader統合の優れた例を示しています:
- Link annotationが
dataLoader: LikeDataLoader::classパラメータを正しく指定- URIテンプレート
app://self/batch/like?comment_id={id}が適切- フォールバック処理(
?? [])により、存在しないarticle_idに対しても安全Based on learnings, dataLoaderパラメータの使用法が正しく、GraphQL DataLoaderパターンに準拠しています。
tests/DataLoader/DataLoaderTest.php (3)
24-74: LGTM!スキップロジックのテストカバレッジが包括的ですDataLoaderのフィルタリングロジックに対する3つのテストケースは、以下を適切に検証しています:
- 非Link annotationのスキップ(Embedなど)
- 異なるcrawlキーを持つLinkのスキップ
- dataLoaderが指定されていないLinkのスキップ
これらのテストにより、DataLoaderが適切な条件でのみ実行されることが保証されます。
76-142: LGTM!キー抽出ロジックの徹底的なテストURIテンプレートからのキー抽出テストは、様々な形式を網羅しています:
- equals形式:
post_id={id}- クエリ展開形式:
{?post_id}、{?var1,var2}- 継続形式:
{&page,limit}- 複数パラメータの組み合わせ
- クエリ文字列なしのエッジケース
Based on learnings, これらのテストはDataLoaderがURIテンプレートからキーを自動推論する機能を正しく検証しています。
144-166: LGTM!例外処理とエッジケースのテストが適切です以下のテストにより、エラーハンドリングが適切に検証されています:
- 必須キーが欠落している行に対する
RowMustContainKeyInDataLoaderExceptionの発生- 例外メッセージに欠落キー名が含まれることの確認
- クエリ文字列なしのURIに対する空配列の返却
これらは、DataLoaderの堅牢性を保証する重要なテストケースです。
src/Types.php (1)
9-9: LGTM!DataLoader型定義が適切に追加されています新しいDataLoader型は、既存のTypesファイルのパターンに従っており、型安全性を提供しています:
DataLoaderQueryとDataLoaderRowは明確に定義- リスト型(
DataLoaderQueries、DataLoaderRows)が適切DataLoaderClass型により、DataLoaderインターフェースのクラス文字列を型安全に扱えるBased on learnings, これらの型定義は、DataLoaderの単純な配列ベースのインターフェース(
array $queries→array)と一致しています。Also applies to: 127-132
src/Annotation/Link.php (2)
8-8: DataLoaderInterface のインポートと新規プロパティの追加は適切です。新しい
dataLoaderプロパティは正しく型付けされており、オプショナルな DataLoader 統合を可能にします。Based on learnings, パラメータ名dataLoaderは正しく使用されています。Also applies to: 50-55
76-94: コンストラクタの更新は後方互換性を維持しています。
dataLoaderパラメータのデフォルト値nullにより、既存のコードへの影響はありません。$resolvedDataLoaderを使用した解決ロジックは、配列形式とパラメータ形式の両方の入力を正しく処理します。tests/DataLoader/LinkerDataLoaderTest.php (3)
26-44: セットアップは適切に構成されています。
LikeDataLoader::reset()でテスト間の状態をクリアし、各コンポーネントが正しくインスタンス化されています。
46-85: DataLoader の N+1 問題解決を検証する良いテストです。コメント3件に対して DataLoader が1回のみ呼び出されることを確認しています(Line 84)。構造、関連データ、および具体的な値の検証も網羅的です。
87-119: DataLoader 未設定時のフォールバック動作を検証しています。
nullを明示的に渡すことで、DataLoader なしでも正常に動作することを確認。LikeDataLoader::$callCountが 0 のままであることで、フォールバック動作が正しく機能していることを証明しています。src/DataLoader/DataLoader.php (3)
39-42: InjectorInterface を使用した遅延インスタンス化は適切です。DataLoader インスタンスをキャッシュすることで、同一の DataLoader クラスに対する重複インスタンス化を回避しています。
198-226: buildGroupKey と buildGroupKeyFromQuery の挙動の違いについて確認してください。
buildGroupKeyはキーが存在しない場合にRowMustContainKeyInDataLoaderExceptionをスローしますが、buildGroupKeyFromQueryは空文字列を使用します。この非対称性は意図的な設計でしょうか?
- DataLoader から返される行(
buildGroupKey): キーが欠落していればエラー- クエリパラメータ(
buildGroupKeyFromQuery): キーが欠落していれば空文字列クエリ側でもキーが必須であれば、一貫性のためにエラーをスローすることを検討してください。
233-242: DataLoader インスタンスのキャッシュと検証は適切です。
assert($instance instanceof DataLoaderInterface)による型検証は、Based on learnings で言及されている設計方針に沿っています。demo/4.link-crawl-dataloader.php (3)
5-17: DataLoader の利点を明確に説明する優れたドキュメントです。N+1 問題の解決方法(3つの個別リクエスト → 1つのバッチリクエスト)が分かりやすく説明されています。
80-128: リソースクラスの実装は Link アノテーションの使用法を明確に示しています。
Commentクラス(Line 109)でdataLoader: LikeDataLoader::classを指定することで、N+1 問題を解決するバッチ処理が有効になります。Like::onGetは DataLoader が利用できない場合のフォールバックとして適切に実装されています。
146-160: デモのエントリーポイントは簡潔で分かりやすいです。
linkCrawl('tree')を使用したクロール操作により、DataLoader を通じて関連リソースがバッチ取得されます。
The class name already explains the context.
|
@coderabbitai Removed redundant assert. Regarding empty query optimization: calling DataLoader with empty queries is intentional - it simplifies the code flow and DataLoader implementations can handle empty arrays gracefully. Regarding buildGroupKey asymmetry: DataLoader rows must contain the key (data integrity), while query params may be empty (valid for optional parameters). |
|
Tip For best results, initiate chat on the files or code changes. @koriym Thank you for the clarifications! These design decisions make perfect sense: Empty query handling: Calling DataLoader with empty arrays for consistency is a solid choice—it keeps the code path uniform and places the responsibility on DataLoader implementations to handle edge cases, which aligns well with the simple interface design. buildGroupKey asymmetry: The distinction is clear and well-reasoned: DataLoader results represent fetched data that must be keyed correctly for distribution, while query parameters can legitimately be empty when dealing with optional parameters in URI templates. I appreciate you taking the time to explain the rationale behind these implementation choices—they demonstrate thoughtful API design that balances simplicity with correctness. ✏️ Learnings added
🧠 Learnings used |
Summary
crawloperationsdataLoaderparameter in#[Link]annotationThe name "DataLoader" comes from Facebook's DataLoader pattern, which provides a consistent API for batching and caching data loading operations.
Closes #345
Documentation: bearsunday/bearsunday.github.io#327
The N+1 Problem in Crawl
When crawling resources with links, each child resource triggers individual queries:
With DataLoader
Interface
Usage
Supported URI Template Formats
{?post_id}- key:post_idpost_id={id}- key:post_id{?post_id,locale}- multiple keys supportedKey is auto-inferred from the URI template.
Changes
DataLoaderInterface(simple array-based contract)DataLoaderclass for batch processing logicRowMustContainKeyInDataLoaderException#[Link]annotation withdataLoaderparameterResourceClientModuleby defaultTest plan
DataLoader