fix: make the fetch order actually take effect, and quieten its failure paths - #194
Merged
Conversation
A batch is handed out in full before the queue is queried again, so the polling fetch size is also how often the UrlQueueOrder is re-evaluated. At 1000 a crawl whose frontier fits in one batch proceeds level by level no matter which order is configured: depthFirstUrlQueueOrder, newestFirstUrlQueueOrder and randomUrlQueueOrder all degenerate into the discovery order and only reorder siblings. Measured against a live crawl of a 10-page fixture, all five orders produced the same breadth-first shape at 1000 and their intended shapes at 1. 100 keeps the query count negligible next to the cost of fetching the pages themselves while making the order mean something on ordinary sites. The javadoc now says what the number controls, and DepthFirstUrlQueueOrder's existing caveat spells out the single-batch case. Adds a test that pins the semantics: with a batch of 2, a deeper URL offered while the batch is being consumed still waits for the following batch.
… page Both weigher call sites logged the exception at WARN, so a weigher that fails consistently prints one full stack trace for every page that has children - the same problem that was already fixed one file over for an unresolvable crawl.order value. The stack trace moves to DEBUG and the WARN stays a single line. The wording was also wrong. A weigher that throws part way through has already mutated some of the batch, so "Falling back to inherited weights" claims more than the code does; the entries are queued with whatever weights the weigher left behind. The DefaultResponseProcessor message now names the parent URL and the CrawlerThread one the number of children, so a repeated warning points at which page tripped it.
Neither javadoc said which to reach for. The pair only differs in what happens between entries of equal weight: sequentialUrlQueueOrder falls back to discovery order, weightFirstUrlQueueOrder lets the index decide. SequentialUrlQueueOrder now states that weight is its primary key, which is the fact that gets missed - a UrlQueueWeigher changes the fetch order under the default with no crawl.order setting at all. WeightFirstUrlQueueOrder now says what it is for, a backlog scored by a weigher where only the score should decide what is crawled next, and warns that without a weigher every entry ties and the order means nothing.
marevol
force-pushed
the
fix/queue-order-followups
branch
from
August 30, 2026 03:45
7be652c to
8707407
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-ups from verifying #193 against a live Fess + OpenSearch. Each item was measured on a real crawl, not inferred.
The polling batch made every order look the same
fetchUrlQueueListhands out a whole batch before querying the queue again, so the polling fetch size is also how often theUrlQueueOrderis consulted. At 1000, a crawl whose frontier fits in one batch proceeds level by level whatever is configured — the sort only reorders siblings. On a 10-page fixture all five orders produced an identical breadth-first shape at 1000, and their intended shapes at 1.Lowered to 100. On a 901-page fixture (300 branches, depth 3) with
depthFirstUrlQueueOrder:A batch of
Bagainst a levelWURLs wide dives roughlyW / Btimes, so this is a proportional improvement rather than a strict depth-first search —DepthFirstUrlQueueOrder's javadoc already said as much and now spells out the single-batch case. The extra queue queries are negligible next to fetching the pages themselves.A new test pins the semantics directly: with a batch of 2, a deeper URL offered while the batch is being consumed still waits for the following batch.
A failing weigher printed a stack trace per page
Both weigher call sites logged the exception at WARN, so a weigher that fails consistently produced one full stack trace for every page with children — the same problem already fixed one file over for an unresolvable
crawl.order. Measured: 7 pages with children, 7 stack traces; now 7 single lines and the traces at DEBUG.The wording was also wrong. A weigher that throws part way through has already mutated part of the batch, so "Falling back to inherited weights" claims more than the code does. The messages now name the parent URL (or the child count) so a repeated warning points at the page that tripped it.
Neither weight-based order said which to reach for
sequentialUrlQueueOrderisweight DESC, createTime ASC;weightFirstUrlQueueOrderisweight DESC. They differ only between entries of equal weight, and the fact that gets missed is that weight is already the default order's primary key — aUrlQueueWeigherchanges the fetch order with nocrawl.ordersetting at all. Confirmed live: with a weigher scoring/a/=3.0,/b/=2.0,/c/=1.0 andcrawl.orderunset, the crawl came back strictly weight-ordered within each level.Both javadocs now say this, and
WeightFirstUrlQueueOrder's says what it is for — a large weighted backlog where only the score should decide what comes next, with no bias towards whatever was discovered first — and warns that without a weigher every entry ties and the order has nothing to sort by.For the record, the second sort field is not what makes the difference at scale. On a queue-shaped index of 2,000,000 entries,
size=100, two runs:weight DESCweight DESC, createTime ASCThe single-field sort is consistently cheaper only when every entry ties, which is the case where its result is arbitrary anyway; once weights differ the two are within noise of each other. Either way it is milliseconds per queue poll, i.e. per 100 URLs.
Tests
mvn -B clean installpasses: 2044 / 15 / 52 across the three modules, no failures.fess-docs is updated in codelibs/fess-docs#514; the matching Fess change is codelibs/fess#3354.