JCR-SQL - содержит функцию, не экранирующую специальные символы?
У меня есть следующая строка запроса:
SELECT jcr:title, jcr:created, jcr:description FROM cq:PageContent WHERE jcr:path LIKE '/content/.../%' AND CONTAINS (., '*') ORDER BY date ASC
Проблема заключается в том, что запрос возвращает все узлы с заданного пути, даже если они не имеют звездочки в каком-либо объекте. Я хотел избежать символа звездочки, но результат тот же. Я пробовал что-то вроде этого:
SELECT jcr:title, jcr:created, jcr:description FROM cq:PageContent WHERE jcr:path LIKE '/content/.../%' AND CONTAINS (., '\*') ORDER BY date ASC
или даже как то так:
SELECT jcr:title, jcr:created, jcr:description FROM cq:PageContent WHERE jcr:path LIKE '/content/.../%' AND CONTAINS (., '\*\*\*\*\*\*\*\*\*\*\*') ORDER BY date ASC
Во всех этих запросах результат один и тот же, даже если ни одна из этих страниц не имеет свойства, которое содержит символ звездочки (или 11 из них)
Документация по функции jcr: содержит:
Внутри литеральных поисковых выражений экземпляры одинарной кавычки ("'"), двойная кавычка ("" ") и дефис (" - ") должны быть экранированы с помощью обратной косой черты (" \ "). Поэтому саму обратную косую черту также следует экранировать, заканчивая тем, что как двойной обратный слеш ("\").
Другие персонажи, такие как *
не упоминаются, поэтому он должен работать даже без выхода (?). Пожалуйста, дайте мне понять, почему я получаю такие результаты здесь и как правильно избежать таких символов.
3 ответа
Я не уверен, если jcr:contains
это правильный метод для вас. Может быть jcr:like
это лучший подход для того, что вы хотите.
jcr:contains
является полнотекстовым поиском и использует индекс lucene. Так что это может иметь неожиданные последствия. Это также не может так легко комбинироваться с другими индексами.
jcr:like
это сравнение атрибутов с подстановочными знаками. И этот подстановочный знак можно экранировать с помощью обратной косой черты. ( https://docs.adobe.com/docs/en/spec/jcr/1.0/6.6.5.1_jcr_like_Function.html)
1-й пример запроса SQL-2
Поиск узлов cq:PageContent с * в любом атрибуте. % (Знак процента) является символом подстановки. * Ищется.
SELECT * FROM [cq:PageContent] AS content
WHERE ISDESCENDANTNODE('/content/myproject/...')
AND content.* LIKE '%*%'
2-й пример запроса SQL-2
Поиск узлов cq:PageContent с% в любом атрибуте. Поэтому знак процента экранируется символом \% (и окружен символом подстановки%).
SELECT * FROM [cq:PageContent] AS content
WHERE ISDESCENDANTNODE('/content/myproject/...')
AND content.* LIKE '%\%%'
3-й пример XPath Query
Почти так же, как последний, так же, как запрос XPath. Только я просто не знаю, как можно искать любой атрибут. Таким образом, этот пример ищет атрибуты jcr:title.
/jcr:root/content/myproject/...//element(*, cq:PageContent)[jcr:like(@jcr:title, '%\%%')]
В вашей документации есть ответ. Существуют специальные символы, которые вы должны экранировать, но если вы хотите, чтобы что-то буквальное, такое как звездочка, соответствовало только символу '*', вы должны использовать escape-символ, который является обратной косой чертой. Документация утверждает, что это немного сбивает с толку, так это то, что сама по себе обратная косая черта является специальным символом при разборе строки, поэтому, если вы хотите, чтобы обратная косая черта рассматривалась как escape-символ, вам нужно ее экранировать.
Другими словами, чтобы избежать звездочки, нужно записать ее как
\\*
Я наконец-то нашел ответ на вики-странице Jackrabbit
Экранирование текста в полнотекстовых (содержит) предложения
Дуб Jackrabbit использует грамматику Apache Lucene для полнотекстового поиска. Таким образом, чтобы избежать пользовательского текста для использования в контейнерах, вам необходимо либо отфильтровать все специальные символы, либо экранировать их. Так, например, чтобы отфильтровать специальные символы, используйте:
String filteredContains = searchTerm.replaceAll("[\\Q+-&|!(){}[]^\"~*?:\\/\\E]", ""); String q = "/jcr:root/foo/element(*, foo)" + "[jcr:contains(@title, '" + filteredContains.replaceAll("'", "''") + "')]" + "[@itemID = '" + itemID.replaceAll("'", "''") + "']";
Только для Jackrabbit 2.x: используйте
Text.escapeIllegalXpathSearchChars(...)
для вызовов в jcr: содержит (...) (см. также JCR-1248):
String q = "/jcr:root/foo/element(*, foo)" + "[jcr:contains(@title, '" + Text.escapeIllegalXpathSearchChars(searchTerm).replaceAll("'", "''") + "')]" + "[@itemID = '" + itemID.replaceAll("'", "''") + "']";