MarkLogic9使用cts:not-query/cts:and-not-query组合查询无结果问题排查
问题原因
你的查询没有返回预期结果,核心是两个配置问题导致否定查询的匹配范围超出了你的预期:
- 第一,
cts:element-value-query默认使用标点不敏感的匹配规则,ABC/*中的斜杠会被作为标点忽略,实际匹配规则等价于ABC*,因此纯文本ABC也会被该查询命中。 - 第二,你看到第二个查询单独运行返回3条结果,是因为返回的3条文档本身就同时包含
ABC和ABC/xxx类型的值,你没感知到纯ABC也会被该查询匹配,当两个查询组合时,所有命中第一个查询的文档都会被否定查询排除,最终结果为空。
你提供的查询计划也能佐证这个问题:计划中已经将CTPA(你实际测试用的关键词,与示例中ABC等价)提取为独立词项进行匹配,说明通配逻辑已经覆盖了纯关键词本身。
解决方法
方案1:修正通配查询的匹配规则
给cts:element-value-query添加punctuation-sensitive选项,确保斜杠会被作为有效字符参与匹配,这样ABC/*只会匹配ABC后接斜杠的内容,不会命中纯ABC:
xquery version "1.0-ml"; import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy"; search:resolve( <cts:and-not-query> <cts:positive> <cts:path-range-query operator="=" xmlns:ns1="http://ns1"> <cts:path-expression>//ns1:security/ns1:elem</cts:path-expression> <cts:value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">ABC</cts:value> </cts:path-range-query> </cts:positive> <cts:negative> <cts:element-query> <cts:element xmlns:ns1="http://ns1">ns1:security</cts:element> <cts:element-value-query> <cts:element xmlns:ns1="http://ns1">ns1:elem</cts:element> <cts:text xml:lang="en">ABC/*</cts:text> <cts:option>wildcarded</cts:option> <cts:option>punctuation-sensitive</cts:option> </cts:element-value-query> </cts:element-query> </cts:negative> </cts:and-not-query> )
方案2:使用范围查询实现排除逻辑(更稳定)
直接用cts:path-range-query的starts-with算子实现排除,不受分词和匹配敏感度规则影响,结果更可控:
xquery version "1.0-ml"; import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy"; search:resolve( <cts:and-not-query> <cts:positive> <cts:path-range-query operator="=" xmlns:ns1="http://ns1"> <cts:path-expression>//ns1:security/ns1:elem</cts:path-expression> <cts:value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">ABC</cts:value> </cts:path-range-query> </cts:positive> <cts:negative> <cts:path-range-query operator="starts-with" xmlns:ns1="http://ns1"> <cts:path-expression>//ns1:security/ns1:elem</cts:path-expression> <cts:value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">ABC/</cts:value> </cts:path-range-query> </cts:negative> </cts:and-not-query> )
使用该方案需要确保你已经为//ns1:security/ns1:elem路径配置了字符串类型的范围索引,和你第一个查询使用的索引一致即可。
额外注意
如果你的数据中不同的ns1:security节点属于同一个文档,还需要确认查询的片段根配置是否为ns1:security,否则查询会在整个文档粒度进行匹配,只要文档内有一个ns1:elem符合否定条件,整个文档都会被排除。
内容的提问来源于stack exchange,提问作者Fred A.
相关产品推荐
相关产品推荐

