2017-01-24 5 views
1

Ich habe eine Datenbank von XML-Dokumente enthält, die grob als solche aussehen:Marklogic - immer unterschiedliche Werte

<document> 
    <question_item> 
    <question>What is your name?</question> 
    </question_item> 
    <question_item> 
    <question>What is your address?</question> 
    </question_item> 
... 
</document> 

Ich mag eine eigene Liste von Fragen einen Suchbegriff zu übernehmen zu können und dann zurück, wo dieser Begriff ist gefunden z Nach "Name" mit den obigen Daten zu suchen, würde ein Ergebnis zurückgeben, "Wie heißt du?".

Ich habe dies erfolgreich mit fn:distinct-values implementiert, aber offensichtlich ist das nicht effizient.

Ich möchte dies mit CTS implementieren. Ich habe Folgendes versucht:

Dies führt jedoch dazu, dass Fragen zurückkommen, die keinen "Namen" im Fragetext haben. z.B. Im obigen Beispiel werden beide Fragen zurückgegeben. Ich denke, dies liegt daran, dass die Abfrage, die ich verwende, ungefiltert weitergegeben wird und daher alle Fragen von einem Fragment zurückgibt, wenn es eine Übereinstimmung für dieses Fragment gibt.

Ist diese Annahme richtig?

Was kann ich tun, um zu erreichen, was ich tun möchte - effizient?

Danke!

Antwort

5

Das ist richtig; cts:element-values() ist eine lexikonartige Funktion, also läuft sie ungefiltert.

Der effizienteste Weg, dies zu tun, ist wahrscheinlich eine passende Lexikon Funktion wie cts:element-value-match zu verwenden:

cts:element-value-match(xs:QName('question'), "* name*") 

Der Haken ist, dass dieser Bereich Indizes verwendet direkt die passende zu tun, die nicht über einige die Funktionen von cts:search -basierte Abfragen, wie linguistic stemming, sind aber die schnellsten. So zum Beispiel, alle Fälle zu behandeln, in dem Sie „name“ passen wollen könnte, könnten Sie eine ausführlichere Reihe von Abfragen erstellen müssen:

cts:element-value-match(xs:QName('question'), ("* name?", "name *", "* name *")) 

Wenn die Grenzen der Platzhalter stellen keine Probleme Ihre Anwendung, dann ist dies der effizienteste Weg, um diese Werte abzufragen, angesichts der Struktur Ihrer Dokumente.

Eine Kompromisslösung, die noch cts:queries verwendet und schnell genug für Ihre Zwecke sein kann, ist es, die Werte zu filtern, nachdem sie die Abfrage:

for $v in cts:element-values(xs:QName('question'),(),(), 
    cts:element-word-query(xs:QName('question'), 'name')) 
where cts:contains($v, cts:word-query('name')) 
return $v 
+0

Danke wst, wirklich hilfreich. Seltsamerweise ist die zweite (Kompromiss-) Abfrage, die Sie zur Verfügung gestellt haben, viel schneller (10x) als die erste. Irgendeine Idee warum das wäre? Ich bin sehr froh, dass der zweite schnell ist. – Robert

+0

@Robert Auch bei einem Speicher-Mapped-Bereichsindex sind Platzhalter (besonders führende Platzhalter) etwas teuer. Da Sie diese in der Abfrage mit dem universellen Index nicht benötigen, sieht es so aus, als ob in Ihrer Anwendung die Kosten für Platzhalter höher sind als die zu filternden Kosten. Die Waage könnte in die andere Richtung kippen, wenn Sie 10-100x die Anzahl der Dokumente und/oder Dokumente mit vielen weiteren Fehlalarmen haben, die gefiltert werden müssten.Grundsätzlich können die Größe, das Volumen und die Struktur Ihrer Dokumente einen großen Einfluss darauf haben, welche Art von Abfrage am schnellsten ist. – wst

+0

Ausgezeichnete Antwort. Vielen Dank! – Robert

2

Haben Sie darüber nachgedacht, jeden question_item in einer separaten Datei zu speichern? Auf diese Weise würden Sie keine Filterung benötigen, und Sie könnten Ihren Code unverändert ausführen.

HTH!