source: MDRepository/trunk/xquery/cmd-model.xqm @ 618

Last change on this file since 618 was 618, checked in by ljo, 14 years ago

First take on new getCollections

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.8 KB
Line 
1module namespace cmd-model = "http://spraakbanken.gu.se/clarin/xquery/model";
2
3(:
4 $Id: cmd-model.xqm 618 2010-08-11 14:45:50Z ljo $
5:)
6
7import module namespace xdb="http://exist-db.org/xquery/xmldb";
8import module namespace util="http://exist-db.org/xquery/util";
9
10declare variable $cmd-model:cmdiDatabaseURI as xs:string := "xmldb:exist:///db";
11
12declare variable $cmd-model:commonFreqsPath as xs:string := "/db/common/clarin/freqs";
13declare variable $cmd-model:cmdiMirrorPath as xs:string := "/db/cmdi-mirror";
14
15declare variable $cmd-model:getCollections as xs:string := "getCollections";
16declare variable $cmd-model:queryModel as xs:string := "queryModel";
17declare variable $cmd-model:searchRetrieve as xs:string := "searchRetrieve";
18
19declare variable $cmd-model:typeActorPath as xs:string := "MDGroup/Actors/Actor";
20declare variable $cmd-model:typeActorPath0 as xs:string := "Actor";
21declare variable $cmd-model:typeActorRolePath as xs:string := "MDGroup/Actors/Actor/Role";
22
23declare variable $cmd-model:docTypeTerms as xs:string := "Terms";
24declare variable $cmd-model:docTypeSuffix as xs:string := "Values";
25
26declare variable $cmd-model:responseFormatXml as xs:string := "xml";
27declare variable $cmd-model:responseFormatJSon as xs:string := "json";
28declare variable $cmd-model:responseFormatText as xs:string := "text";
29
30declare variable $cmd-model:collectionDocName as xs:string := "collection.xml";
31
32declare variable $cmd-model:xmlExt as xs:string := ".xml";
33
34declare function cmd-model:elem($collection as xs:string, $path as xs:string, $depth as xs:integer) as element() {
35  let $path-nodes := util:eval(fn:concat("collection('", $collection, "')//", $path))
36  let $path-count := count($path-nodes)
37   
38  let $subs := distinct-values($path-nodes/child::element()/name())
39  let $text-nodes := $path-nodes//text()
40  let $text-count := count($text-nodes)
41  let $text-count-distinct := count(distinct-values($text-nodes))
42  return 
43        <Term path="{fn:concat("//", $path)}" name="{text:groups($path, "/([^/]+)$")[last()]}" count="{$path-count}" count_text="{$text-count}"  count_distinct_text="{$text-count-distinct}">{
44          if ($depth > 0) then
45            for $elname in $subs[. != '']
46            return
47              cmd-model:elem($collection, concat($path, '/', $elname), $depth - 1)
48          else 'maxdepth'
49        }</Term>
50};
51
52declare function cmd-model:paths($n) {
53        for $el in $n
54        return <Term name="{$el/name()}"> {
55        for $anc in $el/parent::element()
56        return util:node-xpath($anc)
57        }</Term>
58};
59
60(:
61
62:)
63declare function cmd-model:recurse-collections-model($collection as xs:string, $type-name as xs:string, $depth as xs:integer) as item()* {
64    let $children := xdb:get-child-collections($collection)
65    return
66      if (fn:exists($children)) then
67          let $child-results :=
68            for $child in $children
69            return
70              cmd-model:recurse-collections-model(fn:concat($collection, '/', xs:string($child)), $type-name, $depth),
71              $current := cmd-model:create-doc($collection, $type-name, $depth)
72          return ($current, $child-results)
73      else
74        cmd-model:create-doc($collection, $type-name, $depth)
75};
76
77(:
78  Recurse for collections
79:)
80declare function cmd-model:recurse-collections($collection as node()+, $parent as xs:string, $depth as xs:integer) as item()* {
81    let $children := if ($depth eq 0) then () else $collection//ResourceProxy[ResourceType = "Metadata"]
82    return
83      if (fn:exists($children)) then
84          let $child-results :=
85            for $child in $children
86              let $child-doc := doc(concat(util:collection-name($child/root()), "/", $child/ResourceRef)),
87                $child-name := ($child-doc//Corpus/Name, "UNKNOWN")[1]
88            return if (empty($child-doc)) then <no-target>{util:collection-name($child/root())}</no-target> else
89              cmd-model:recurse-collections($child-doc, $child-name, $depth - 1)
90          return
91          <c n="{$parent}" cnt="{sum($child-results/@cnt)}">{$child-results}</c>
92      else
93      <c n="{$parent}" cnt="{count($collection//CMD)}"></c>
94};
95
96(:
97
98:)
99declare function cmd-model:create-doc($collection as xs:string, $type-name as xs:string, $depth as xs:integer) as xs:string* {
100  (: if newer data available :)
101    cmd-model:store-result($collection, cmd-model:elem($collection, $type-name, $depth), $type-name, $depth)
102  (:else () :)
103};
104
105(:
106
107:)
108declare function cmd-model:get-result-doc($collection as xs:string, $type-name as xs:string, $depth as xs:integer) as item()* {
109  let $name-last := text:groups($type-name, "/(\w+)$")[last()],
110    $new-name := if (fn:empty($name-last)) then $type-name else $name-last,
111    $dummy := if (cmd-model:is-result-available($collection, fn:concat("/", $new-name, xs:string($depth)))) then
112    ()
113    else
114      cmd-model:create-doc($collection, $type-name, $depth)
115    return
116      fn:doc(fn:concat($collection, "/", $new-name, xs:string($depth), $cmd-model:xmlExt))
117};
118
119(:
120 Generic get-doc(collection, docname)
121:)
122declare function cmd-model:get-doc($collection as xs:string, $doc-name as xs:string) as item()* {
123      fn:doc(fn:concat($collection, "/", $doc-name))
124};
125
126
127(:
128  Function for telling wether the result is already available or not.
129:)
130declare function cmd-model:is-result-available($collection as xs:string, $result-ref as xs:string) as xs:boolean {
131  fn:doc-available(fn:concat($collection, $result-ref, $cmd-model:xmlExt))
132};
133
134(:
135  Function for telling wether the document is available or not.
136:)
137declare function cmd-model:is-doc-available($collection as xs:string, $doc-name as xs:string) as xs:boolean {
138  fn:doc-available(fn:concat($collection, "/", $doc-name))
139};
140
141(:
142  Store the calculated frequencies for reuse.
143  If more than one collection is given the result is stored in the common
144  collection for reuse.
145:)
146declare function cmd-model:store-result($coll-names as xs:string+, $entries as element()*, $type-name as xs:string, $depth as xs:integer) as xs:string {
147  let $clarin-writer := fn:doc("/db/clarin/writer.xml"),
148    $dummy := xdb:login($cmd-model:cmdiDatabaseURI, $clarin-writer//write-user/text(), $clarin-writer//write-user-cred/text())
149    return
150   
151      if (fn:exists($coll-names[2])) then
152        (: Det gÀller fler Àn en samling. :)
153        xdb:store($cmd-model:commonFreqsPath, cmd-model:make-compound-doc-name($coll-names, $type-name, $depth), cmd-model:make-doc-element-of-type($type-name, $coll-names, $entries, $depth))
154      else
155        (: Det gÀller endast en samling. :)
156        let $dummy := util:log('debug', fn:concat('Stores ', $type-name, ' in ', $coll-names))
157        return xdb:store($coll-names, cmd-model:make-doc-name($coll-names, $type-name, xs:string($depth), fn:false()), cmd-model:make-doc-element-of-type($type-name, (), $entries, xs:string($depth)))
158};
159
160(:
161  Store the collection listing in give collection.
162:)
163declare function cmd-model:store-collection-data($data as node(), $collection-path as xs:string, $doc-name as xs:string) as xs:string? {
164  let $clarin-writer := fn:doc("/db/clarin/writer.xml"),
165  $dummy := xdb:login($cmd-model:cmdiDatabaseURI, $clarin-writer//write-user/text(), $clarin-writer//write-user-cred/text())
166  return 
167      (: util:catch("org.exist.xquery.XPathException", :) xdb:store($collection-path, $doc-name, $data)(: , ()) :)
168};
169
170(:
171  Create document name for type () with or without collection path.
172:)
173declare function cmd-model:make-doc-name($coll-name as xs:string?, $type-name as xs:string, $depth as xs:string, $incl-path as xs:boolean) as xs:string {
174  let $doc-name := fn:concat($type-name, $depth, $cmd-model:xmlExt)
175  return
176    if ($incl-path) then
177      fn:concat($coll-name, "/", $doc-name)
178    else
179      $doc-name
180};
181
182(:
183  Create document name with md5-hash for selected collections (or types) for reuse.
184:)
185declare function cmd-model:make-compound-doc-name($coll-names as xs:string+, $type-name as xs:string, $depth as xs:string) as xs:string {
186  let $name-prefix := fn:concat($type-name, $depth)
187    return
188    fn:concat($name-prefix, "-", util:hash(string-join($coll-names, ""), "MD5"), $cmd-model:xmlExt)
189};
190
191(:
192  Skapa ett element av angiven typ.
193:)
194declare function cmd-model:make-element-of-type($type-name as xs:string, $count as xs:string, $text-count as xs:string, $text-types-count as xs:string, $value as xs:string) as element() {
195  element {$type-name} {
196
197      attribute count {$freq},
198      attribute text-count {$rank},
199      attribute text-types-count {$text-types},
200      text {$value} 
201  }
202};
203
204(:
205  Skapa ett dokumentelement av angiven typ.
206:)
207declare function cmd-model:make-doc-element-of-type($type-name as xs:string, $coll-names as xs:string*, $entries as element()*, $depth as xs:string) as element() {
208      let $depth-value := attribute depth {$depth},
209      $coll-names-value := if (fn:empty($coll-names)) then () else attribute colls {fn:string-join($coll-names, ",")}
210      return
211        element {cmd-model:get-doc-type-element-name($type-name)} {
212          $depth-value,
213          $coll-names-value,
214          attribute created {fn:current-dateTime()},
215          $entries
216        }
217};
218
219(:
220  Skapa elementnamn för dokumentet av typ.
221:)
222declare function cmd-model:get-doc-type-element-name($type-name as xs:string) as xs:string {
223  $cmd-model:docTypeTerms
224};
225
226
227
228
229(:
230  Seraliseringsformat.
231:)
232declare function cmd-model:serialise-as($item as node()?, $format as xs:string) as item()? {
233      if ($format eq $cmd-model:responseFormatJSon) then
234        let $option := util:declare-option("exist:serialize", "method=text media-type=application/json")
235          return
236           (: json:xml-to-json($item) :) $item
237      else (: $cmd-model:responseFormatXml, $cmd-model:responseFormatText:)
238        $item
239};
240
241
242(:~
243  API function queryModel.
244:)
245declare function cmd-model:query-model($cmd-index-path as xs:string, $collection as xs:string+, $format as xs:string, $max-depth as xs:integer) as item() {
246        cmd-model:serialise-as(cmd-model:get-result-doc($collection, $cmd-index-path, $max-depth), $format)
247};
248
249(:~
250  API function getCollections.
251:)
252declare function cmd-model:get-collections($collections as xs:string+, $format as xs:string, $max-depth as xs:integer) as item() {
253  let $names := if (exists($collections[2])) then
254    ($cmd-model:commonFreqsPath, cmd-model:make-compound-doc-name($collections, "collection", $max-depth)) 
255  else
256    ($collections, $cmd-model:collectionDocName),
257 $dummy :=   
258      if (cmd-model:is-doc-available($names[1], $names[2])) then
259        ()
260      else
261        let $children := for $collection-item in $collections
262          let $collection-item-doc := collection(concat($collection-item, "/", "Corpusstructure"))
263        return
264          cmd-model:recurse-collections($collection-item-doc, "", $max-depth)
265          return
266            cmd-model:store-collection-data(<Collections count="{count($children)}" root="{$collections}">{$children}</Collections>, $names[1], $names[2])
267return 
268  cmd-model:serialise-as(cmd-model:get-doc($names[1], $names[2]), $format)
269};
270
271(:~
272  API function searchRetrieve.
273:)
274declare function cmd-model:search-retrieve($cql-query as xs:string, $collection as xs:string+, $format as xs:string, $start-item as xs:integer, $end-item as xs:integer) as item()* {
275  let $results := for $coll in $collection return util:eval(fn:concat("collection('", xdb:decode($coll), "')", xdb:decode($cql-query), "/ancestor::CMD")),
276    $result-count := fn:count($results),
277    $result-seq := fn:subsequence($results, $start-item, $end-item),
278    $seq-count := fn:count($result-seq),
279    $result-fragment :=
280    <searchRetrieveResponse>
281      <numberOfRecords>{$result-count}</numberOfRecords>
282      <echoedSearchRetrieveRequest>{$cql-query, $collection, $start-item, $end-item}</echoedSearchRetrieveRequest>
283      <diagnostics>{$seq-count}</diagnostics>
284      <records>
285        {$result-seq}
286      </records>
287    </searchRetrieveResponse>
288
289    return
290        cmd-model:serialise-as($result-fragment, $format)
291
292};
293(:
294{cmdComponent}   //{cmdComponent}        Actor   //Actor
295{cmdPath}.      //{cmdPath}/{cmdComponent}      Actor.Contact.Phone     //Actor/Contact/Phone
296{cmdIndex} {rel} {term}         //{cmdIndex}[\. {rel} '{term}']         Actors.Actor.Sex=f      //Actors/Actor/Sex[.='f']
297{cmdIndex} any {term}   //{cmdIndex}[contains(. '{term}')]      Organisation.Name any University        //Organisation/Name[contains(.,'University')]
298and, or, and not        ?!      Organisation.Name any University and Actor.gender=m     ?!
299
300//MDGroup[Actors/Actor/Role[.='sponsor'] and Actors/Actor/Name[contains(.,'a')]]
301//Title[starts-with(.,'a')]
302//Title[starts-with(.,'A')]
303//Title[contains(.,'analysis')]
304http://demo.spraakdata.gu.se/clarin/cmd/model/stats?operation=searchRetrieve&query=//Title[contains(.,'analysis')]&collection=
305
306<record>
307  <recordSchema>info:srw/schema/1/dc-v1.1</recordSchema>
308  <recordPacking>xml</recordPacking>
309  <recordData>
310    <srw_dc:dc xmlns:srw_dc="info:srw/schema/1/dc-v1.1">
311     <dc:title>This is a Sample Record</dc:title>
312    </srw_dc:dc>
313  </recordData>
314  <recordPosition>1</recordPosition>
315  <extraRecordData>
316    <rel:score xmlns:rel="info:srw/extensions/2/rel-1.0">
317      0.965
318    </rel:rank>
319   </extraRecordData>
320</record>
321
322<searchRetrieveResponse>
323        <numberOfRecords>integer</numberOfRecords>
324        <echoedSearchRetrieveRequest>query itself (together with the context-collection) </echoedSearchRetrieveRequest>
325        <diagnostics>if necessary</diagnostics>
326        <records>
327                ....
328        </records>
329</searchRetrieveResponse>
330
331:)
Note: See TracBrowser for help on using the repository browser.