Jackrabbit ищет через соединенные узлы - PullRequest
6 голосов
/ 26 марта 2012

Я отметил объекты в хранилище Jackrabbit (на самом деле это CRX Adobe / Day CQ, но я думаю, что это код Jackrabbit):

  • asset: tags = A, B
    • данные дочерних активов 1: теги = A, C, E
    • данные дочерних активов 2: теги = D, E

Я хочу выполнить запрос кобъединение набора тегов родительского ресурса и одного дочернего элемента, т. е. «BC» будет соответствовать ресурсу, потому что у нас есть те из них, что в родительском и дочернем элементах 1, но «CD» не будет совпадать, поскольку отсутствует комбинация родительского и одного дочернего элементовпотому что C и D разделены между отдельными дочерними узлами данных.

Есть ли способ сделать это в Jackrabbit?Мы можем написать запрос XPath

\\element(*, dam:Asset)[(@tags = 'C' or *\@tags='C')
                        and (@tags = 'D' or *\@tags='D')]

, но это не сработает, поскольку XPath, похоже, не гарантирует, что присоединенные дочерние активы * одинаковы, то есть это означает, что "любой дочерний элемент имеет C /D "и так будет соответствовать моему активу, потому что у 1+ детей есть C, а у 1+ детей есть D. Вместо этого я мог бы использовать JCR-SQL2

SELECT * FROM dam:Asset as asset
  LEFT OUTER JOIN nt:unstructured as child ON ISCHILDNODE(child,asset)
  WHERE (asset.tags = 'C' or child.tags = 'C')
    AND (asset.tags = 'D' or child.tags = 'D')

, но в JCR-SQL2 нет SELECT DISTINCT:если вместо этого я выполню поиск «BE», я получу этот актив дважды, потому что он совпадает с активом + child1 и активом + child2.

Я мог бы постобработать любой результат запроса в Java, то есть отфильтровать ложноположительные совпадения дляв первом случае или отфильтровывать повторяющиеся результаты для второго случая, но я нервничаю, как это повлияет на производительность подкачки: мне нужно отсканировать больше узлов, чем необходимо, чтобы отсеять поврежденные узлы, и мне нужно отсканировать партиювычислить правильный размер результата для подкачки.Это должно быть дешевле для второго случая SQL2, потому что, если мой поиск упорядочен, я могу обнаружить дубликаты на основе только пути к узлу, и все дубликаты будут последовательными, поэтому я могу найти данные данной страницы с помощью дешевого сканирования только, надеюсь, без чтениявесь узел для каждого результата, но я не знаю стоимость сканирования всех результатов для подсчета подкачки, даже для простого случая только для пути.

Еще один вариант, который мы рассмотрели, - это денормализация тегов.в один узел.В этом случае, чтобы обеспечить точный поиск, это должно означать создание нового атрибута комбинированного_круга в каждом дочернем узле и выполнение всех поисков только для набора дочерних узлов.Однако это все еще страдает от отдельной проблемы, если мы сопоставим два дочерних узла под одним и тем же ресурсом.

Спасибо за любые предложения.Это уже большой пример, и его нужно будет масштабировать дальше.Я видел другие вопросы, в которых говорится, что ModeShape является реализацией JCR, которая имеет SELECT DISTINCT, но я думаю, что переключение на ModeShape только для этого должно быть последним средством, если действительно возможно разместить CQ на ModeShape.


Одна из идей, которую мы пришли сейчас, состоит в том, чтобы вычислить каждое объединение тегов актива и дочерних тегов и объединить теги в одну строку, а затем записать каждое значение как многозначное свойство актива, т.е. asset + child1= "ABCE" и asset + child2 = "ABDE", поэтому мы получаем

  • asset: tags = A, B;tagUnions = "ABCE", "ABDE"

Пока мы определяем фиксированный порядок объединения тегов в строку (например, в алфавитном порядке), мы можем искать любую комбинацию, используя tagUnions LIKE '%B%C%' (кроме Iиспользовать реальные разделители между тегами в реальном случае).Хотя это будет работать, насколько мы можем видеть, мне это не очень нравится: потенциально большое количество тегов на каждый актив + дочерний элемент, все с более длинными именами, чем отдельные буквы, означают, что в итоге мы получим длинные строки, выполняющие запросы LIKEна всех из них, которые, вероятно, не могут быть эффективно проиндексированы.

Еще один способ сделать это - создать битовую маску: определить A = 1, B = 2 и т. д. и сохранить здесь многозначный целочисленный массив, а затем выполнитьпобитовое сравнение.Однако это, вероятно, ограничено 64 различными тегами, и, поскольку у нас их более 1000, я не думаю, что мы сможем это сделать, даже если JCR поддерживает побитовые операции, чего, как я ожидаю, не будет.

Так что я все еще в поисках чистого решения, похожего на базу данных для этого.Вы пропустили награду, которую я выложил, но все еще есть галочки, голоса и благодарность за любую помощь.

1 Ответ

1 голос
/ 29 марта 2012

С список рассылки Apache Jackrabbit :

Да, к сожалению, запросы на объединение не поддерживаются.Любая работа в этой области будет высоко оценена.

Между тем, лучшим обходным решением, вероятно, является выполнение двух отдельных запросов и явное выполнение объединения в коде приложения путем объединения двух наборов результатов.

Итак, это как вариант.Глядя на предоставленный вами SQL:

, но в JCR-SQL2 нет SELECT DISTINCT: если вместо этого я буду искать «BE», я получу этот актив дважды, потому что он соответствует обоим активам +child1 и asset + child2.

Я посмотрел на возможные решения, поддерживаемые Jackrabbit, и пришел с пустыми руками.Тем не менее, я согласен с решением, представленным здесь :

Я сделал простой SELECT с соответствующими ORDER BY ... затем каждый раз, когда я использовал строку, язаверил, что это не то же самое, что и предыдущий: -)

(Sics сохранены.)

Хотя ORDER BY потенциально сомнительно, если вам не требуется сортировка на основе базы данных,Что-то мешает вам создать хэш-набор в вашем контроллере, чтобы ограничить результаты только уникальными значениями с помощью JCR API?

...