jnioche opened a new pull request, #2252:
URL: https://github.com/apache/stormcrawler/pull/2252

   Related to #158.
   
   jsoup's `Element.selectXpath()` is not DOM-free: on every call it converts 
the whole document to a W3C DOM (`NodeUtils.selectXpath` → `W3CDom.fromJsoup`), 
creates a new `XPathFactory` and compiles the expression. `jsoup.XPathFilter` 
calls it at least once per key and `jsoup.LinkParseFilter` once per pattern, so 
a page was converted once per expression evaluated.
   
   ## Changes
   
   - `jsoup.XPathFilter` builds the W3C DOM once per page (`W3CContext`, 
namespace-unaware as in jsoup's `selectXpath`) and evaluates all its 
expressions against it, mapping the results back to the jsoup elements with 
`W3CDom.sourceNodes()`.
   - The XPath expressions are compiled once, when the filter is configured.
   - `jsoup.LinkParseFilter` uses the same shared context.
   
   The extraction syntax (`/tidyText()`, `/allText()`, `/html()`, `/@attr`) and 
the results are unchanged.
   
   ## Performance
   
   Old vs new `XPathFilter` + `LinkParseFilter` with the archetype's 
`jsoupfilters.json` (6 XPath expressions over 4 keys + 1 link pattern), on the 
test pages from `core/src/test/resources`. Average time per page after warm-up, 
single thread, JDK 17. The outputs (metadata and outlinks) were checked to be 
identical.
   
   | page | size | jsoup parse | W3C conversion | before | after | speedup |
   |---|---:|---:|---:|---:|---:|---:|
   | stormcrawler.apache.org.html | 7 KB | 0.05 ms | 0.08 ms | 0.69 ms | 0.38 
ms | 1.8x |
   | stackexception.html | 173 KB | 16.7 ms | 12.9 ms | 75.6 ms | 35.2 ms | 
2.1x |
   | longtext.html | 5.7 MB (mostly text) | 5.6 ms | 0.10 ms | 0.69 ms | 0.40 
ms | 1.7x |
   
   On a page with a large DOM, a single W3C conversion costs about as much as 
the jsoup parsing itself; before this change the two filters converted the page 
~5 times, taking more than 4x the time spent parsing it. On small pages the 
gain comes mostly from no longer creating an `XPathFactory` and compiling the 
expressions on every call. The gain grows with the number of expressions 
configured.
   
   ## Behaviour changes
   
   - An invalid XPath expression now fails when the filter is configured 
("Can't compile expression") instead of being logged on every page.
   - jsoup's `W3CDom.XPathFactoryProperty` system property (to plug in another 
XPath engine) is no longer taken into account; expressions are compiled with 
the default JDK `XPathFactory`.
   
   ## Not covered
   
   Each filter still does its own conversion, so a configuration with both 
`XPathFilter` and `LinkParseFilter` (as in the archetypes) converts the page 
twice. Sharing the W3C DOM across filters would require caching it per page, 
which could be stale if a previous JSoupFilter modified the document.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to