Может ли XQuery поддерживать запрос древовидной структуры?

Я реализовал механизм запросов древовидной структуры, используя sql и дизайн базы данных на основе атрибутов значений сущностей. Я хотел увидеть производительность той же функциональности с подходом, основанным на XQuery, предполагая, что можно было бы использовать XQuery для этой задачи. Упрощенная форма моего дерева (документ XLM) выглядит следующим образом:введите описание изображения здесь

Существуют разные типы узлов, но единственным атрибутом, который я использую в запросе, является атрибут узла archetype_node_id. Тестовый запрос, который я попытался написать, направлен на то, чтобы выбрать узел оценки (справа) с двумя узлами элемента. Реализация запроса требует двух ключевых возможностей из используемого языка: способность поддерживать структурные определения (с логическими операторами) и способность определять ограничения для атрибутов узлов (в данном случае атрибутов xml).

С XQuery у меня есть две проблемы: 1) мне не удается объявить ссылки на все интересующие узлы, то есть любой узел, который меня интересует на графике 2) я не могу понять, как вернуть совпадения, поскольку совпадения для правой части этого дерева будут иметь одну композицию с оценкой, которая в свою очередь имеет два элемента.

Вот моя первая наивная попытка использования FLWR:

    for     $composition in doc("composition-visit.xml")//element()
let    $evaluation := (
                        for $evalsneeded in $composition//element() 
                        let $elementat02 := 
                                            (for $el02 in $evalsneeded//element() 

                                             where $el02/@archetype_node_id = 'at0002'
                                                  and exists($evalsneeded//$el02)
                                             return  $el02
                                            ),
                            $elementat03 := 
                                        (for $el03 in $evalsneeded//element() 

                                         where $el03/@archetype_node_id = 'at0003'
                                                and exists($evalsneeded//$el03)
                                         return  $el03
                                        )
                        where $evalsneeded/@archetype_node_id = 'openEHR-EHR-EVALUATION.goal.v1'
                                 and 
                                    exists ($evalsneeded//$elementat02)
                                     and
                                     exists ($evalsneeded//$elementat03)

                        return $evalsneeded)
where $composition/@archetype_node_id = 'openEHR-EHR-COMPOSITION.encounter.v1'                
        and exists($composition//$evaluation)


return $evaluation/@archetype_node_id/string(.)

Моя проблема заключается в том, что я в конечном итоге отправляю оценки и узлы элементов в подзапросы, поскольку фильтрация по их значениям атрибутов и расположению не работает, если я представляю их как глобальные переменные в основном теле FLOWR.

Я еще более невежествен, когда дело доходит до возвращения результатов, но я не хотел задавать отдельный вопрос для этого.

В идеале, когда я применяю ограничение AND для оценки, имеющей элементы с кодами at0002 и at0003, я должен получить правую часть дерева, а если я использую ограничение OR для тех же элементов, я должен получить все дерево.

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

Обновление: вот моя вторая попытка. Это действительно открывает дверь к тому, что я пытался сделать, но я не уверен, что это правильный способ сделать это в XQuery. Должен ли я задать еще один вопрос для улучшения этого подхода?:

    <result>
{
    for     $composition in doc("composition-visit.xml")//element() 

    where $composition/@archetype_node_id = 'openEHR-EHR-COMPOSITION.encounter.v1'                


    return <composition>
                <name>{$composition/name/value/string(.)}</name>
                <evaluation>{for $eval in $composition//element()
                             let $el1 := (for $el1_in_eval in $eval//element()
                                            where $el1_in_eval/@archetype_node_id = 'at0002'
                                            return $el1_in_eval ),
                                 $el2 := (for $el2_in_eval in $eval//element()
                                            where $el2_in_eval/@archetype_node_id = 'at0003'
                                            return $el2_in_eval )

                                     where $eval/@archetype_node_id = 'openEHR-EHR-EVALUATION.goal.v1'
                                            and
                                            (exists($el1)
                                            and
                                            exists($el2)
                                            )
                                     return <eval>
                                                   <name>{$eval/name/value/string(.)}</name>
                                                   <element1>{for $element1 in $eval//element()
                                                             where $element1/@archetype_node_id = 'at0002'

                                                             return $element1}</element1>
                                                     <element2>{for $element2 in $eval//element()
                                                     where $element2/@archetype_node_id = 'at0003'

                                                     return $element2}</element2>
                                           </eval>
                            }</evaluation>
            </composition>
}
</result>

По сути, я применяю отношения родитель / потомок с помощью операторов let и использую return для получения значений соответствующих совпадений для let, что, в свою очередь, может сделать то же самое в дереве.

2 ответа

Похоже, ваш вариант использования запрашивает "архетипированные" данные openEHR.

Не стесняйтесь взглянуть на открытый исходный код https://github.com/LiU-IMT/EEE который использует xQuery для запросов, аналогичных вашему сценарию использования, но с данными, смоделированными немного по-другому.

Он используется, например, в статье http://www.ep.liu.se/ecp/070/009/ecp1270009.pdf где вы можете найти пример запроса, который возвращает все идентификаторы записей, которые имели результат гистологического исследования, указывая на опухолевые поражения между 2006-01-01 и 2006-05-01.

В AQL (Archetype Query Language) это выражается как...

SELECT e/ehr_id/value as ehr_id
FROM Ehr e
CONTAINS VERSION v
CONTAINS COMPOSITION c [openEHR-EHR-COMPOSITION.histologic_exam.v1]
CONTAINS OBSERVATION obs [openEHR-EHR-   OBSERVATION.histological_exam_result.v1]
WHERE (EXISTS obs/data[at0001]/events[at0002]/data[at0003]/items[at0085]/items[at0033]/items[at0034] 
OR
EXISTS obs/data[at0001]/events[at0002]/data[at0003]/items[at0085]/items[at0033]/items[at0035])
AND c/context/start_time/value >= '2006-01-01T00:00:00,000+01:00'
AND c/context/start_time/value < '2006-05-01T00:00:00,000+01:00'`

... который при автоматическом разборе и переводе в XQuery выглядит следующим образом:

declare namespace v1 = "http://schemas.openehr.org/v1";
declare default element namespace "http://schemas.openehr.org/v1";
declare namespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
declare namespace eee = "http://www.imt.liu.se/mi/ehr/2010/EEE-v1.xsd";
declare namespace res = "http://www.imt.liu.se/mi/ehr/2010/xml-result-v1#";
<res:xml-results>
<res:head><res:variable name="ehr_id"/></res:head>
<res:results>
 {let $ehrRoot := //eee:EHR
  for $e in $ehrRoot
  for $v in $e/eee:versioned_objects/eee:versions
  for $c in $v//*[@xsi:type='v1:COMPOSITION' and @archetype_node_id="openEHR-EHR-COMPOSITION.histologic_exam.v1"]
  for $obs in $c//*[@xsi:type='v1:OBSERVATION' and @archetype_node_id= "openEHR-EHR-OBSERVATION.histological_exam_result.v1"]
  where
   (
    exists($obs/data[@archetype_node_id = 'at0001']/events[@archetype_node_id = 'at0002']/data[@archetype_node_id='at0003']/items[@archetype_node_id = 'at0085']/items[@archetype_node_id = 'at0033']/items[@archetype_node_id = 'at0034'])
   or
    exists($obs/data[@archetype_node_id = 'at0001']/events[@archetype_node_ id = 'at0002']/data[@archetype_node_id = 'at0003']/items[@archetype_node_id = 'at0085']/items[@archetype_node_id = 'at0033']/items[@archetype_node_id = 'at0035'])
   )
   and
    $c/context/start_time/value >= '2006-01-01T00:00:00,000+01:00' 
   and 
    $c/context/start_time/value < '2006-05-01T00:00:00,000+01:00'
return
<res:result><res:binding name="ehr_id">{$e/eee:ehr_id/value}</res:binding></res:result>}
</res:results>
</res:xml-results>

Эту модель также стоит попробовать в вашем случае использования. Более подробную информацию о решении и контексте можно найти в документе http://www.biomedcentral.com/1472-6947/13/57

Если дерево является бинарным деревом поиска, оно было реализовано с использованием XQuery. Смотрите этот пост:

http://dnovatchev.wordpress.com/2012/01/09/the-binary-search-tree-data-structurehaving-fun-with-xpath-3-0/

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

Другие вопросы по тегам