Вот упрощенная версия проблемы, над которой я работаю: у меня есть куча XML-данных, которые кодируют информацию о людях. Каждый человек уникально идентифицируется атрибутом id, но он может называться многими именами. Например, в одном документе я могу найти
<person id=1>Paul Mcartney</person>
<person id=2>Ringo Starr</person>
А в другом я могу найти:
<person id=1>Sir Paul McCartney</person>
<person id=2>Richard Starkey</person>
Я хочу использовать xquery для создания нового документа, в котором перечислены все имена, связанные с данным идентификатором. i.e.:
<person id=1>
<name>Paul McCartney</name>
<name>Sir Paul McCartney</name>
<name>James Paul McCartney</name>
</person>
<person id=2>
...
</person>
То, как я делаю это сейчас в xquery, выглядит примерно так (псевдокод-эск):
let $ids := distinct-terms( [all the id attributes on people] )
for $id in $ids
return <person id={$id}>
{
for $unique-name in distinct-values
(
for $name in ( [all names] )
where $name/@id=$id
return $name
)
return <name>{$unique-name}</name>
}
</person>
Проблема в том, что это действительно медленно. Я предполагаю, что узким местом является самый внутренний цикл, который выполняется один раз для каждого идентификатора (которых около 1200). Я имею дело с достаточным количеством данных (300 МБ, разбросано по 800 XML-файлам), поэтому даже одно выполнение запроса во внутреннем цикле занимает около 12 секунд, что означает, что для повторения 1200 раз потребуется около часов (что может быть оптимистично - процесс продолжается уже 3 часа). Это не только медленно, но и использует много виртуальной памяти. Я использую Saxon, и мне пришлось установить максимальный размер кучи Java на 10 ГБ (!), Чтобы избежать ошибок памяти, и в настоящее время он использует 6 ГБ физической памяти.
Так вот, как бы я действительно хотел это сделать (в псевдокоде Pythonic):
persons = {}
for id in ids:
person[id] = set()
for person in all_the_people_in_my_xml_document:
persons[person.id].add(person.name)
Там я только что сделал это за линейное время, с помощью всего лишь одной развертки документа xml. Теперь, есть ли способ сделать что-то подобное в xquery? Конечно, если я могу себе это представить, разумный язык программирования должен быть в состоянии сделать это (сказал он в шутку). Проблема, я полагаю, в том, что в отличие от Python, xquery не имеет (насколько я знаю) ничего похожего на ассоциативный массив.
Есть ли какой-нибудь умный способ обойти это? В противном случае, есть ли что-то лучше, чем xquery, который я мог бы использовать для достижения своей цели? Потому что на самом деле вычислительные ресурсы, которые я использую для решения этой относительно простой задачи, просто смешны.