Поиск Jackrabbit по объединенным узлам

У меня есть тегированные объекты в репозитории Jackrabbit (на самом деле Adobe/Day CQ CRX, но я думаю, что это код Jackrabbit):

  • актив: теги = 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')

но там нет SELECT DISTINCT в JCR-SQL2: если вместо этого я ищу "B E", я получу этот актив дважды, потому что это соответствует как активу + child1, так и актив + child2.

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

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

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

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

  • актив: теги = A, B; tagUnions = "A B C E", "A B D E"

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

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

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

1 ответ

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

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

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

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

но там нет SELECT DISTINCT в JCR-SQL2: если вместо этого я ищу "B E" Я получу этот актив дважды, потому что это соответствует актив + ребенок1 и актив + ребенок2.

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

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

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

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

licensed under cc by-sa 3.0 with attribution.