2016-04-28 9 views
1

Ich verwende derzeit Saxon, um Xquery in unserer .NET-Anwendung zu verarbeiten. Wir arbeiten mit sehr großen XML-Dateien (~ 2 GB). Wenn die Xquery gegen eine dieser Dateien mit der Saxon-Binärdatei direkt ausgeführt wird, beträgt die Zeit für die Auswertung etwa 2 Minuten. Bei der Auswertung meiner C# -Anwendung erhöht sich die verstrichene Zeit jedoch auf etwa 10 Minuten Ich konnte noch nicht erkennen, was ich falsch mache.Wie kann man die Geschwindigkeit der sächsischen Auswertung in C# erhöhen?

Das ist, was ich tue, wenn ich den XQuery mit der Sächsischen Binärdatei über die Befehlszeile:

Query.exe -config:config.xml -q:XQueryTest.txt 

Dies sind die Inhalte der config.xml:

<configuration xmlns="http://saxon.sf.net/ns/configuration" edition="HE"> 
    <xquery defaultElementNamespace="http://www.irs.gov/efile"/> 
</configuration> 

Und XQueryTest.txt enthält die Xquery, die wir verarbeiten werden. Wenn Sie die Xquery über die Befehlszeile ausführen, ändern wir sie so, dass sie die Datei angibt, mit der wir sie ausführen werden, indem Sie die Funktion doc() verwenden. Hier ist eine Beispielzeile:

for 
    $ReturnData at $currentReturnDataPos in if(exists(doc("2GB.XML")/Return/ReturnData)) then doc("2GB.XML")/Return/ReturnData else element{'ReturnData'} {''} 

Wie oben erwähnt, dauert die Ausführung dieses Befehls ca. 2 Minuten.

Jetzt ist das, was ich in meiner .NET-Anwendung mache, um diese gleiche Bewertung zu machen.

Processor processor = new Processor(); 
DocumentBuilder documentBuilder = processor.NewDocumentBuilder(); 
documentBuilder.IsLineNumbering = true; 
documentBuilder.WhitespacePolicy = WhitespacePolicy.PreserveAll; 
XQueryCompiler compiler = processor.NewXQueryCompiler(); 

string query = BuildXqueryString(); 

if (!String.IsNullOrEmpty(query)) 
{ 
    XQueryExecutable executable = compiler.Compile(query); 
    XQueryEvaluator evaluator = executable.Load(); 

    using (XmlReader myReader = XmlReader.Create(@"C:\Users\Administrator\Desktop\2GB.xml")) 
    { 
     evaluator.ContextItem = documentBuilder.Build(myReader); 
    } 

    var evaluations = evaluator.Evaluate(); 
} 

Das Problem, das wir haben, ist in dieser Zeile: evaluator.ContextItem = documentBuilder.Build(myReader). Was ist nicht einmal die Auswertung, sondern nur das Laden der Datei. Diese Zeile benötigt einfach zu viel Zeit, und ich muss wissen, ob das erwartet wird oder ob es eine Möglichkeit gibt, die Geschwindigkeit zu erhöhen. Ich habe alle verschiedenen Überladungen der Build() Methode verwendet und sie nehmen alle viel Zeit in Anspruch, viel mehr als die 2 Minuten, die die Ausführung benötigt, wenn sie von der Befehlszeile ausgeführt wird.

In Bezug auf die Streaming-Kapazität von Saxon, um die Datei nach Teilen zu lesen, wegen der Xqueries, die wir generieren, ist das keine Option, da die Xquery Informationen in einem beliebigen Teil des XML kombinieren kann.

+0

http://stackoverflow.com/questions/2415434/the-limitation-on-the-size-of-net-array zeigt, dass die maximale Größe eines zugewiesenen Objekts in .NET 2 GB ist. Vielleicht kommt Saxon in ein .NET-Speicherproblem und muss zusätzliche Schritte unternehmen, die die Binärdatei möglicherweise nicht ausführen muss? Vielleicht würde das Betrachten der verwendeten Ressourcen zeigen, dass die Binärdatei zusätzlichen Speicher verwenden kann? Tut mir leid, ich habe nichts anderes oder spezifische Erfahrung mit Saxon. Prost! – chryosolo

Antwort

1

Wir haben ein ähnliches 5-zu-1-Verhältnis zwischen Saxon auf der Java-Plattform und Saxon auf der .NET-Plattform in einigen Fällen gesehen, und wir sind nicht auf den Grund gekommen, warum es trotz umfangreicher Untersuchung geschieht. Ein Teil des Grundes ist, dass es inkonsistent scheint. Als wir Saxon zum ersten Mal über .NET mit dem IKVMC-Cross-Compiler lieferten, war das Verhältnis viel besser, mit nur ca. 25% Overhead auf .NET, aber seitdem gab es eine Reihe von Änderungen in der Technologie: Java-VMs haben wurde schneller, IKVMC hat von der Verwendung der GNU-Classpath-Bibliothek zu OpenJDK umgeschaltet, und .NET selbst ist nicht stehen geblieben.

Es ist neu für mich, dass der gleiche Code viel schneller von der .NET-Befehlszeile als von der .NET-API ausgeführt werden soll.

Der große Unterschied hier ist, dass Saxon das Dokument mit dem Apache Xerces-Parser (konvertiert in .NET-Code mit IKVMC) erstellt, während Sie DocumentBuilder.build() in der gezeigten Weise verwenden verwenden Sie den Microsoft XmlReader.

Ich würde erwarten, dass der Dokumentenaufbau am schnellsten abläuft, wenn Sie einen (Dateisystem-) URI bereitstellen, aber ich kann nicht sagen, dass ich ihn gemessen habe. Es könnte sich lohnen, einige Experimente (vielleicht mit kleineren Dateien) zu machen und uns die Ergebnisse zu zeigen. Oder haben Sie versucht, die Methode doc() aus Ihrer Anwendung zu verwenden, anstatt zuerst das Dokument zu erstellen?

+0

Wir dachten auch, dass die Verwendung eines URI uns bessere Ergebnisse bringen würde, aber das war überhaupt nicht der Fall, es war immer noch sehr langsam. Wir haben versucht, Ihre letzte Empfehlung zu verwenden (warum haben wir nicht daran gedacht?), Und tatsächlich wurde die Geschwindigkeit stark erhöht. Es ist immer noch etwas langsamer (etwas mehr als 3 Minuten), aber nicht annähernd die letzten 10 Minuten, was großartig ist! Ich denke, wir haben nie über diesen Ansatz nachgedacht, weil wir dachten, dass die korrekte Implementierung zuerst das XML laden und dann das generische Xquery dagegen ausführen sollte, anstatt den XML-Pfad innerhalb des Xquery fest zu codieren. Danke !! – Ricardo

+0

Danke für die Info. Es gibt hier einige seltsame Effekte, die ich nicht verstehe: Wir müssen sehen, ob wir das reproduzieren können. –

+0

Loggte eine Saxon-Ausgabe hier: https://saxonica.plan.io/issues/2729 –

0

Die langsame Leistung wird verursacht, indem .NET XmlReader das Parsing verwendet. Die Push/Pull-SAX-Eventing-Behandlung mit dem .NET-XML-Parser und dem Saxon-Empfänger ist viel langsamer als die direkte Verwendung des JAXP-Xerces-Parsers, der in Saxon bereitgestellt wird.

Um die JAXP-Parser zu erzwingen, sollten Sie Folgendes tun können arbeiten:

evaluator.ContextItem = documentBuilder.Build (new Uri ("file: /// C: \ Users \ Administrator \ Desktop \ 2GB.xml "));