3

こんにちは、marklogic と Xquery の世界は初めてです。Marklogic Xquery で次のロジックを記述するための出発点を考えることができません。次のことを達成できるように、誰かがアイデア/サンプルを提供してくれるとありがたいです:

B.XML の単語検索に基づいて A.XML を照会したいと考えています。クエリは C.XML を生成する必要があります。ロジックは次のようになります。

A.XML

<root>
<content> The state passed its first ban on using a handheld cellphone while driving in 2004 Nokia Vodafone Nokia Growth Recession Creicket HBO</content>
</root>

B.XML

<WordLookUp>
<companies>
    <company name="Vodafone">Vodafone</company>
    <company name="Nokia">Nokia</company>
</companies>
<topics>
    <topic group="Sports">Cricket</topic>
    <topic group="Entertainment">HBO</topic>
    <topic group="Finance">GDP</topic>
</topics>
<moods>
    <mood number="4">Growth</mood>
    <mood number="-5">Depression</mood>
    <mood number="-3">Recession</mood>
</moods>

C.XML (結果 XML)

<root>
    <content> The state passed its first ban on using a handheld cellphone while driving in 2004 Nokia Vodafone Nokia Growth Recession Creicket HBO</content>
    <updatedElement>
        <companies>
            <company count="1">Vodafone</company>
            <company count="2">Nokia</company>
        </companies>
        <mood>1</mood>
        <topics>
             <topic count="1">Sports</topic>
             <topic count="1">Entertainment</topic>
        </topics>
            <word-count>22</word-count>
    </updatedElement>
    </root>
  1. A.xml の各 company/text() を B.xml で検索し、一致する場合はタグを作成: TAG {company count="その単語の出現回数"}company/@name {/company}

  2. A.xml の各 topic/text() を B.xml で検索し、一致するものが見つかった場合は、タグ TAG を作成します {topic topic="その単語の出現回数"}topic/@group{/topic}

  3. B.xml 内の A.xml のそれぞれの気分/テキスト() を検索し、一致が見つかった場合 [最初の単語の出現回数 * {/mood[最初の単語]/@number}] + [2 番目の単語の出現回数 * {/mood[2 番目の単語] ]/@番号})]....

  4. 要素の単語数を取得します。

4

3 に答える 3

2

これは楽しいものでした。その過程でいくつかのことを学びました。ありがとう!

注: 必要な結果を得るために、A.xml のタイプミスを修正しました ("Creicket" -> "Cricket")。

次のソリューションでは、MarkLogic 固有の関数を 2 つ使用します。

  • cts:highlight(一致するテキストをノードに置き換えてから数えることができます)
  • cts:tokenize(特定の文字列を単語、スペース、および句読点の部分に分割するため)

また、これら 2 つの機能にそれぞれ固有の強力な魔法もいくつか含まれています。

  • 特殊変数の動的バインディング$cts:text(この特定のユース ケースでは実際には必要ありませんが、余談になります)、および
  • のこれらのサブタイプを追加するデータ モデル拡張xs:string:
    • cts:word
    • cts:space、 と
    • cts:punctuation.

楽しみ!

xquery version "1.0-ml";

(: Generic function using MarkLogic's ability to find query matches within a single node :)
declare function local:find-matches($content, $search-text) {
  cts:highlight($content, $search-text, <MATCH>{$cts:text}</MATCH>)
  //MATCH
};

(: Generic function using MarkLogic's ability to tokenize text into words, punctuation, and spaces :)
declare function local:get-words($text) {
  cts:tokenize($text)[. instance of cts:word]
};

(: The rest of this is pure XQuery :)
let $content := doc("A.xml")/root/content,
    $lookup  := doc("B.xml")/WordLookUp
return
  <root>
    {$content}
    <updatedElement>

      <companies>{
        for $company in $lookup/companies/company
        let $results := local:find-matches($content, string($company))
        where exists($results)
        return
          <company count="{count($results)}">{string($company/@name)}</company>
      }</companies>

      <mood>{
        sum(
          for $mood in $lookup/moods/mood
          let $results := local:find-matches($content, string($mood))
          return count($results) * $mood/@number
        )
      }</mood>

      <topics>{
        for $topic in $lookup/topics/topic
        let $results := local:find-matches($content, string($topic))
        where exists($results)
        return
          <topic count="{count($results)}">{string($topic/@group)}</topic>
      }</topics>

      <word-count>{
        count(local:get-words($content))
      }</word-count>

    </updatedElement>
  </root>

上記のすべてがどのように機能するかについて、追加の質問がある場合はお知らせください。最初は、MarkLogic での検索のパンとバターであ​​るcts:searchまたはを使用する傾向がありました。cts:containsしかし、この例は検索 (ドキュメントの検索) ではなく、既に指定されたドキュメント内で一致するテキストを検索するものであることに気付きました。これを何らかの形で拡張して多数のドキュメントに集約する必要がある場合は、cts:searchorの追加の使用を検討する必要がありcts:containsます。

最後の警告: コンテンツに既に要素が含まれていると思われる場合は<MATCH>、呼び出すときに別の要素名を使用することをお勧めしcts:highlightます (コンテンツの既存の要素名と競合しないことが保証できる名前)。そうしないと、間違った数の結果が得られる可能性があります (正確な数よりも多くなります)。

補遺:

すでにテキストがすべての単語に分割されていることcts:highlightを考えると、これが なしで実行できるかどうか興味がありました. cts:tokenize次の別の実装を使用しても、同じ結果が生成さlocal:find-matchesれます (ただし、関数宣言の順序が互いに依存しているため、関数宣言の順序を交換する必要があります)。

(: Find word matches by comparing them one-by-one :)
declare function local:find-matches($content, $search-text) {
  local:get-words($content)[cts:stem(.) = cts:stem($search-text)]
};

指定された単語を語幹に正規化するために使用cts:stemされるため、たとえば「pass」を検索すると「passed」などと一致します。ただし、これは複数単語 (フレーズ) 検索では機能しません。したがって、念のためcts:highlight、 と のようcts:searchcts:contains、任意の cts:query を処理できる を使用することに固執します (上記のような単純な単語/フレーズ検索を含む)。

于 2012-04-15T03:50:24.443 に答える
0

一歩下がって、rdbms の代わりにドキュメント指向データベースで使用するためにデータやドキュメントをモデル化する方が良いかどうかを尋ねるのは理にかなっているかもしれません

于 2012-04-15T16:44:38.713 に答える
-1

これは、より単純で短く、完全に準拠したXQueryであり、実装拡張機能は含まれていません。これにより、準拠したXQuery1.0プロセッサで動作します。

let $content := doc('file:///c:/temp/delete/A.xml')/*/*,
      $lookup := doc('file:///c:/temp/delete/B.xml')/*,
      $words := tokenize($content, '\W+')[.]
         return
           <root>
            {$content}
             <updatedElement>
               <companies>
                  {for $c in $lookup/companies/*,
                       $occurs in count(index-of($words, $c))
                     return
                       if($occurs)
                          then
                            <company count="{$occurs}">
                              {$c/text()}
                            </company>
                          else ()
                  }
               </companies>
               <mood>
                  {
                   sum($lookup/moods/*[false or index-of($words, data(.))]/@number)
                  }
               </mood>
               <topics>
                 {for $t in $lookup/topics/*,
                      $occurs in count(index-of($words, $t))
                    return
                      if($occurs)
                         then
                           <topic count="{$occurs}">
                             {data($t/@group)}
                           </topic>
                         else ()
                  }
               </topics>
               <word-count>{count($words)}</word-count>
              </updatedElement>
          </root>

提供されたファイルA.xmlおよびB.XML(ローカルディレクトリに含まれているc:/temp/delete)に適用すると、必要な正しい結果が生成されます。

<root>
   <content> The state passed its first ban on using a handheld cellphone while driving in 2004 Nokia Vodafone Nokia Growth Recession Cricket HBO</content>
   <updatedElement>
      <companies>
         <company count="1">Vodafone</company>
         <company count="2">Nokia</company>
      </companies>
      <mood>1</mood>
      <topics>
         <topic count="1">Sports</topic>
         <topic count="1">Entertainment</topic>
      </topics>
      <word-count>22</word-count>
   </updatedElement>
</root>
于 2012-04-15T18:02:26.337 に答える