サンプル クエリの実行計画により、問題の根本原因が明らかになります。
[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%') */
今、それは同時に速くて厳密でなければなりません。