Skip to content

Fix: O(n²) parent lookup in BFS and duplicate URL enqueue in BestFirst - #2244

Open
yashikam19 wants to merge 1 commit into
unclecode:developfrom
yashikam19:fix/deep-crawl-perf
Open

Fix: O(n²) parent lookup in BFS and duplicate URL enqueue in BestFirst#2244
yashikam19 wants to merge 1 commit into
unclecode:developfrom
yashikam19:fix/deep-crawl-perf

Conversation

@yashikam19

Copy link
Copy Markdown

Fixes #2242

Summary

Fixes two related inefficiencies in the deep-crawl strategies found while
integrating BestFirstCrawlingStrategy for site-wide crawling:

  1. BFSDeepCrawlStrategy._arun_batch/_arun_stream re-scanned the entire
    current_level list to find each result's parent URL - O(n²) for a level
    of size n. Replaced with a dict built once per level (dict(current_level)),
    O(n).
  2. BestFirstCrawlingStrategy only tracked visited (updated at dequeue
    time), so a URL discovered via multiple parent pages before being crawled
    could be pushed onto the priority queue more than once - wasted scorer
    calls and queue slots. Added a queued set updated at enqueue time to
    prevent this.

Both are internal-only fixes - no behavior or public API change, same outputs.

Files Changed

  • crawl4ai/deep_crawling/bfs_strategy.py - build parent_by_url dict once
    per level in _arun_batch and _arun_stream, instead of a linear scan per
    result.
  • crawl4ai/deep_crawling/bff_strategy.py - added a queued: Set[str] tracked
    alongside visited, checked/updated at the point a URL is pushed onto the
    priority queue (both fresh-start and resume-from-state paths).

How Has This Been Tested?

  • pytest tests/deep_crawling/ tests/general/test_deep_crawl*.py: 70 passed,
    0 regressions
  • Isolated benchmark on real production data: pulled djangoproject.com's
    actual sitemap.xml (1000 URLs, one legitimate request, no crawling) and
    timed the parent-lookup code directly - 11.69ms (old) → 0.08ms (new), ~145x.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have added/updated unit tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

…estFirst

- BFSDeepCrawlStrategy: build a per-level {url: parent} dict once instead of
  linearly re-scanning current_level for every fetched result
  (_arun_batch and _arun_stream)
- BestFirstCrawlingStrategy: track a  set at enqueue time, since
   is only populated when a URL is dequeued/processed — without it,
  a URL discovered via multiple parent pages before being crawled could be
  pushed onto the priority queue more than once, wasting a scorer call and a
  queue slot

Fixes unclecode#2242
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant