4

JCR-SQL2 クエリをCONTAINS操作していると、条件にあった文字列とまったく同じ文字列を持たないノードが演算子によって検出されることに気付きました。

次のクエリ:

SELECT * FROM [nt:base] AS s WHERE CONTAINS(s.*, 'my/search-expression')

文字列を含むノードだけでなく、 のmy/search-expressionような文字列を持つノードも検索しますmy/another/search/expression

クエリが提供された正確な文字列しか見つけられないのはなぜですか? 結果を絞り込むためにどのように変更できますか?

この質問は、知識を共有するために自分で回答することを目的としていますが、自由に独自の回答を追加したり、既存の回答を改善したりしてください。

4

2 に答える 2

6

サンプル クエリの実行計画により、問題の根本原因が明らかになります。

  [nt:base] as [s] /* lucene:lucene(/oak:index/lucene) +:fulltext:my +:fulltext:search +:fulltext:expression ft:("my/search-expression") where contains([s].[*], 'my/search-expression') */

オペレーターはCONTAINS全文検索をトリガーします。「/」や「-」などの単語以外の文字は、単語の区切り記号として使用されます。その結果、クエリは、「my」、「search」、および「expression」という単語を含むすべてのノードを検索します。

それを使って何ができますか?いくつかのオプションがあります。

1. 二重引用符を使用する

指定された単語が正確な順序で含まれ、その間に他の単語が含まれていないフレーズに結果を制限したい場合は、検索式を二重引用符で囲みます。

SELECT * FROM [nt:base] AS s WHERE CONTAINS(s.*, '"my/search-expression"')

現在、実行計画は異なります。

[nt:base] as [s] /* lucene:lucene(/oak:index/lucene) :fulltext:"my search expression" ft:("my/search-expression") where contains([s].[*], '"my/search-expression"') */

クエリは、単一の単語ではなく、フレーズ全体を検索するようになりました。ただし、単語以外の文字は引き続き無視されるため、「my search expression」または「my-search-expression」などのフレーズも検出されます。

2. LIKE 式を使用する (非推奨)

LIKE単語以外の文字を保持して正確なフレーズのみを検索する場合は、次の式を使用できます。

SELECT * FROM [nt:base] AS s WHERE s.* LIKE '%my/search-expression%'

ただし、これははるかに遅くなります。実行計画の説明中にタイムアウトを回避するために、別の条件を追加する必要がありました。このクエリの場合:

SELECT * FROM [nt:base] AS s WHERE s.* LIKE '%my/search-expression%'  AND ISDESCENDANTNODE([/content/my/content]) 

実行計画は次のとおりです。

[nt:base] as [s] /* traverse "/content/my/content//*" where ([s].[*] like '%my/search-expression%') and (isdescendantnode([s], [/content/my/content])) */

「my/search-expression」というフレーズを含むノードのみが検索されます。

3. 二重引用符を使用して結果を絞り込む

最初のアプローチ (二重引用符を使用) を使用して、後で結果を絞り込む方がよいでしょう。CONTAINSたとえば、クエリがアプリケーションから実行される場合は、アプリケーション コードで結果を絞り込みます。

4. CONTAINS と LIKE を混ぜる

もう 1 つのオプションは、全文検索とLIKE式をAND次のように組み合わせることです。

SELECT * FROM [nt:base] AS s WHERE CONTAINS(s.*, '"my/search-expression"') AND s.* LIKE '%my/search-expression%'

実行計画は次のとおりです。

[nt:base] as [s] /* lucene:lucene(/oak:index/lucene) :fulltext:"my search expression" ft:("my/search-expression") where (contains([s].[*], '"my/search-expression"')) and ([s].[*] like '%my/search-expression%') */

今、それは同時に速くて厳密でなければなりません。

于 2018-01-03T12:37:21.907 に答える