限制搜索 JSON 嵌套 属性 的 Marklogic 搜索选项

Marklogic Search options to restrict search for a JSON nested property

我有一个 json 具有以下结构

{"scientist":{
         "username": "XXX",
         "name":"XXXX"
          ...
    },
    "registrar":{
      "username": "YYY",
         "name":"aaaaa"
          ...
    }
   }

我想将搜索限制为搜索上面 json 中的嵌套 属性,例如:-- 想搜索 "registrar/username".. 我正在尝试使用search -constraint "container".. 但无法进行搜索.. 以下是我的代码,它似乎不起作用..

嵌套 json 字段搜索还有其他机制吗?

```

let $search := "(username:WHITEMK) AND (concept.registrar: )"

let $options := 
  <options xmlns="http://marklogic.com/appservices/search">
    <constraint name="concept.registrar">
      <container>
        <json-property>registrar</json-property>
      </container>
    </constraint>
    <constraint name="username">
      <value>
        <json-property>username</json-property>
        <term-option>case-insensitive</term-option>
        <term-option>wildcarded</term-option>
      </value>
    </constraint>
    <return-facets>false</return-facets>
    <return-values>false</return-values>
    <return-constraints>false</return-constraints>
    <return-frequencies>false</return-frequencies>
    <return-qtext>false</return-qtext>
    <search-option>unfiltered</search-option>
    <search-option>unfaceted</search-option>
    <search-option>format-json</search-option>
    <search-option>score-simple</search-option>
  </options>

let $start := 1
let $page-length :=10000

return search:search($search, $options, $start, $page-length)

```

谢谢, 拉维

正如今天在讨论列表中指出的那样,如果您在包含的约束之前为容器添加前缀,它应该可以工作,如:

let $search := "concept.registrar:username:WHITEMK"

作为脚注,当您试图了解查询文本的解析方式时,有时先使用 search:parse() 会更容易。

很高兴您找到了短期解决方法。我希望这有助于长期解决方案。

我能够在不添加嵌套字段的情况下获得更通用的版本是通过构建自定义搜索选项,它解析嵌套 JSON 属性 并使用 [=20= 构建搜索查询]-属性-范围查询..
例如:假设您想搜索一些嵌套的 3 级 属性

let $search := "(concept:orfs.aminoAcids.predictedMatureSeqs.domains.heavyChainIsoType:igg1)"

使用自定义解析器我能够将其转换为以下内容

<cts:json-property-scope-query xmlns:cts="http://marklogic.com/cts">
<cts:property>orfs</cts:property>
<cts:json-property-scope-query>
<cts:property>aminoAcids</cts:property>
<cts:json-property-scope-query>
<cts:property>predictedMatureSeqs</cts:property>
<cts:json-property-scope-query>
<cts:property>domains</cts:property>
<cts:json-property-scope-query>
<cts:property>heavyChainIsoType</cts:property>
<cts:word-query>
<cts:text xml:lang="en">igg1</cts:text>
<cts:option>case-insensitive</cts:option>
<cts:option>punctuation-insensitive</cts:option>
<cts:option>whitespace-insensitive</cts:option>
<cts:option>wildcarded</cts:option>
</cts:word-query>
</cts:json-property-scope-query>
</cts:json-property-scope-query>
</cts:json-property-scope-query>
</cts:json-property-scope-query>
</cts:json-property-scope-query>

如果有人感兴趣,下面是自定义解析器的代码

xquery version "1.0-ml";
module namespace gbrsso="http://marklogic.com/gbrs/modules";
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
(:
   This module tries to build a custom constraint.. and takes into account the nested query as well
   for eg: Concept:registrar.username:mamidrx
:)

(: This is parse function which is invoked my marklogic when it sees the custom constraing :)
declare function gbrsso:parse($constraint-qtext as xs:string, $right as schema-element(cts:query)) as schema-element(cts:query){
 let $log := xdmp:log("Constraint-qtext : " || $constraint-qtext)
 let $log := xdmp:log("$right : " || fn:string($right//cts:text/text()))
 let $queryText := fn:string($right//cts:text/text())
 let $qparts := fn:tokenize($right//cts:text/text(), ":")
 let $queryText := $qparts[last()]
 let $log := xdmp:log("$queryText : " || $queryText)

  let $qpartsCnt := fn:count($qparts)

  let $query :=
      if(fn:count($qparts) = 1) then
        <root>{
          cts:word-query($queryText, ("case-insensitive", "wildcarded", "punctuation-insensitive", "whitespace-insensitive"))
          }</root>/*
      else 
        <root>{
          let $qparts := fn:tokenize($qparts[1],"\.") 
          let $endPart := $qparts[last()]
          (: remove the last part in sequence as we need to create word query with it :)
          let $qparts := fn:remove($qparts, fn:count($qparts))
          let $queryExp :=
            if(fn:count($qparts) = 0) then (: checks if it is nested... :)
               cts:json-property-scope-query($endPart, cts:word-query($queryText, ("case-insensitive", "wildcarded", "punctuation-insensitive", "whitespace-insensitive")))
            else
              let $xy := cts:json-property-scope-query($endPart, cts:word-query($queryText, ("case-insensitive", "wildcarded", "punctuation-insensitive", "whitespace-insensitive")))
              return gbrsso:buildQuery($xy, $qparts)

          return $queryExp
        }</root>/*

  return $query

};