Zipunrar
Zipunrar

Reputation: 203

MarkLogic - Search via Max/Min Filter

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.

Upvotes: 0

Views: 223

Answers (2)

BenW
BenW

Reputation: 433

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".

Upvotes: 0

wst
wst

Reputation: 11771

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.

Upvotes: 1

Related Questions