Come posso trovare dati duplicati nel documento XML usando XQuery?
-
22-07-2019 - |
Domanda
Ho un sacco di documenti in un database XML MarkLogic. Un documento ha:
<colors>
<color>red</color>
<color>red</color>
</colors>
Avere più colori non è un problema. Avere più colori che sono entrambi rossi è un problema. Come trovo i documenti che contengono dati duplicati?
Soluzione
Tutto ciò che MarkLogic restituisce è solo una sequenza di nodi, quindi possiamo contare la dimensione della sequenza dell'insieme e confrontarla con il conteggio della sequenza di valori distinti. Se non sono distinti, sono duplicati e hai il tuo sottoinsieme.
for $c in doc()//colors
where fn:count($c/color) != fn:count(fn:distinct-values($c/color))
return $c
Altri suggerimenti
Oppure potresti farlo completamente fuori dagli indici :)
per $ c in doc () // colors
probabilmente creerà un errore CACHE ALBERO ESPANSO su set di dati più grandi.
Ecco un modo leggermente più complicato per attaccare questo quando i dati sono enormi, assicurati che URI Lexicon sia attivato e quindi aggiungi un indice di intervallo di elementi sul elemento colore e calcola i valori di colore distinti che hanno la duplicazione da qualche parte . Quindi passare in rassegna solo i documenti che hanno questo colore uno per uno e calcolare i conteggi di frequenza degli articoli dei colori di interesse nei documenti. Se ottieni una frequenza superiore a 1, questo documento necessita di deduplicazione.
let $qn := xs:QName("color")
let $colorsWithItemFreq := cts:element-values($qn, (), ("ascending", "item-order", "item-frequency"))
let $colorsOfInterest :=
for $color at $i in cts:element-values($qn, (), ("ascending", "item-order", "fragment-frequency"))
let $fragFrequency := cts:frequency($color)
let $itemFrequency := cts:frequency($colorsWithItemFreq[$i])
where $itemFrequency gt $fragFrequency
return
$color
for $uri in cts:uris( (), ("document"), cts:element-value-query($qn, $colorsOfInterest)
let $colorsWithDuplicationInThisDoc :=
for $color in cts:element-values($qn, (), ("item-frequency"), cts:document-query($uri) )
where $color = $colorsOfInterest and cts:frequency($color) gt 1
return
$color
where fn:count( $colorsWithDuplicationInThisDoc ) gt 1
return
$uri
Spero che sia d'aiuto.
Per questo XML:
<?xml version="1.0"?>
<colors>
<color>Red</color>
<color>Red</color>
<color>Blue</color>
</colors>
Utilizzando questo XSD:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method = "text" />
<xsl:strip-space elements="*"/>
<xsl:template match="colors">
<xsl:for-each select="color">
<xsl:variable name="node_color" select="text()"/>
<xsl:variable name="numEntries" select="count(../color[text()=$node_color])"/>
<xsl:if test="$numEntries > 1">
<xsl:text>Color value of </xsl:text><xsl:value-of select="."/><xsl:text> has multiple entries 
</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Ho ottenuto questo output:
Color value of Red has multiple entries
Color value of Red has multiple entries
In modo che almeno li trovino, ma riporterà ogni ricorrenza di un colore ripetuto, non solo ogni colore ripetuto.
Questo dovrebbe fare il trucco. Non conosco troppo MarkLogic, quindi la prima riga per ottenere il set di documenti potrebbe essere errata. Ciò restituirà tutti i documenti che hanno 2 o più elementi di colore con lo stesso valore di stringa.
for $doc in doc()
let $colors = $doc//color/string(.)
where some $color in $colors
satisfies count($colors[. = $color] > 1)
return doc()