2012-03-26 5 views
6

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

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

Я хочу д uery против объединения набора тегов родительского актива и одного дочернего элемента, то есть «BC» будет соответствовать активу, потому что у нас есть те, что находятся в родительском и дочернем 1, но «CD» не будет соответствовать, потому что нет никакой комбинации родительского и одного child, который соответствует этому, поскольку 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, потому что, если мой запрос упорядочен, я могу обнаружить дубликаты на основе пути узла, и все дубликаты будут последовательными, поэтому я могу найти данные, данные по данной странице с дешевым сканированием, только надеемся, без чтения весь узел для каждого результата, но я не знаю, сколько стоит сканирование всех результатов для счета подкачки, даже для простого случая только для путей.

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

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


Одна идеи, которую мы придумали сейчас, чтобы вычислить каждое объединение тегов активов и дочерние тегов и объединить тег в одну строку, а затем записать каждое значение в качестве многозначного свойства актива, т.е.актив + ребенок1 = «A B C E» и актив + ребенок2 = «A B D E», поэтому мы получаем

  • актив: теги = A, B; tagUnions = «ABCE», «ABDE»

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

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

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

ответ

1

От the Apache Jackrabbit mailing list:

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

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

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

но нет в JCR-SQL2 нет SELECT DISTINCT: если вместо этого я искать «B E» я буду получать этот актив возвращается в два раза, потому что это соответствует как актив + child1 и актив + child2.

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

То, что я должен сделать простой SELECT, с присвоенной ПОРЯДКА Bys ... , то каждый раз, когда я использовал строку, я veried, что это не то же самое как предыдущего :-)

(Sics сохранилась.)

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

+0

Спасибо. На самом деле это не SQL 'UNION', который мне нужен в терминах объединения соединений по двум запросам, но я вычисляю совпадение с логическим объединением двух свойств между разными узлами, поэтому это SQL' JOIN' и 'SELECT DISTINCT', которые Мне нужно.Решение, которое вы связываете - заказывайте и удаляйте последовательные дубликаты, - это одна из идей, которые я упомянул в параграфе о результатах последующей обработки, и проблема с этим связана с правильной подкачкой: мне нужно будет сканировать все записи до текущего страницу, где начинается страница, и сканировать все, чтобы получить точное количество общих страниц. – Rup

+0

... и система, с которой я работаю, имеет миллионы активов, поэтому 10 000+ результатов из простого запроса не являются неслыханными - я не могу предположить, что у меня есть небольшое количество результатов, поскольку парень говорит, что у него есть это связанное решение. Думаю, мне нужна сортировка базы данных, чтобы получить эффективный пейджинг. В любом случае документы Jackrabbit рекомендуют вам использовать 'ORDER BY' в любом случае, поскольку заказ по умолчанию JCR (если он отключен в файле repository.xml) потенциально дорог для вычисления. – Rup

+0

@Rup Спасибо за обновление. Как вы помните, пост-обработка результатов на Java возможна, но может быть потенциально дорогостоящей, поскольку вы пересекаете дополнительные узлы, которые вы уже посетили. Таким образом, это сводится к вопросу эффективного обхода вашей структуры данных. Hmn. Я должен посмотреть на это позже и вернуться к вам. :) – MrGomez