0
votes

i want to search documents in MarkLogic.

My documents look like:

<product xmlns="myns/products">
  <id>3114</id>
  <materialNo xml:lang="en">1.1160</materialNo>
  <steelName xml:lang="en">SWRCH24K</steelName>
  <name xml:lang="en">wire, wire rod for cold heading</name>
  <chemicalProperties>
    <chemicalProperty>
      <element>c</element>
      <min>0.1900</min>
      <max>0.2500</max>
    </chemicalProperty>
    <chemicalProperty>
      <element>si</element>
      <min>0.1000</min>
      <max>0.3500</max>
    </chemicalProperty>
    <chemicalProperty>
      <element>mn</element>
      <min>1.3500</min>
      <max>1.6500</max>
    </chemicalProperty>
    <chemicalProperty>
      <element>p</element>
      <max>0.0300</max>
    </chemicalProperty>
  </chemicalProperties>
</product>

So i want to search via max/min values of the chemical properties. To do so i use this xquery search (simple example):

cts:search(/, cts:and-query(
  (cts:collection-query("test"),
   cts:element-value-query(
     fn:QName("myns/products", "name"),
     "wire, wire rod for cold heading"),
   cts:element-query(
     fn:QName("myns/products", "chemicalProperty"),
     cts:and-query(
       (cts:element-value-query(
          fn:QName("myns/products", "element"), "c"),
        cts:or-query(
          (cts:element-range-query(
             fn:QName("myns/products", "max"), "<=", 0.2),
           cts:and-not-query(
             cts:element-range-query(
               fn:QName("myns/products", "min"), "<=", 0.2),
             cts:element-value-query(
               fn:QName("myns/products", "max"), "*")))),
        cts:or-query(
          (cts:element-range-query(
             fn:QName("myns/products", "min"), ">=", 0.1),
           cts:and-not-query(
             cts:element-range-query(
               fn:QName("myns/products", "max"), ">=", 0.1),
             cts:element-value-query(
               fn:QName("myns/products", "min"), "*"))))))))))

The problem is that the query above will return the sample document. The sub-queries (and-not) are there to check if max/min exists. In some cases there could be only min or only max value.

But this document is out of bounds?!

My database does have element range indexes on min and max. All other settings are defaults.

What is the problem? Any suggestions.

UPDATE

Ok, thanks for the suggestions but no. Enabling value position do not solve the problem. However a workaround is to remove the "and-not-query" and replace it with an "and-query" and to add new attributes to the documents:

<chemicalProperty hasMin="0" hasMax="1">...

indexing and querying those attributes works and returns the correct results.

2
If you have a follow up question, please post it as a separate SO question. If this question is relevant, then you can link to it in the new one.wst

2 Answers

1
votes

It's possible that because of your index settings, cts:element-query returns true if the min and max queries match in any <chemicalProperty> in the same document, not constrained to a single <chemicalProperty>. I would only expect to see this in an unfiltered search, however, and I don't see that option in your call to cts:search.

First try enabling element value positions, which should allow the database to exclude matches from different elements using indexes.

An alternative solution is to use cts:near-query to constrain the values in the element query by position.

0
votes

The problem seems to be that you are trying to use wildcards in the cts:element-value-query calls, but not declaring them wildcarded. Since nothing will match the literal "*", the cts:and-not-query does the opposite of what you intend.

You want something like this:

cts:element-value-query( fn:QName("myns/products", "max"), "*", "wildcarded")

cts:element-value-query

Alternatively, you could enable one of the wildcard indexes, and ML will detect wildcard queries automatically.

If neither "wildcarded" nor "unwildcarded" is present, the database configuration and $text determine wildcarding. If the database has any wildcard indexes enabled ("three character searches", "two character searches", "one character searches", or "trailing wildcard searches") and if $text contains either of the wildcard characters '?' or '*', it specifies "wildcarded". Otherwise it specifies "unwildcarded".