XQuery: как последовательно найти появление ожидаемых данных (аналогично конечному автомату)

Добрый день, во-первых, спасибо, что прочитали мой вопрос о XQuery.

Мне нужно реализовать в XQuery функцию для последовательного обнаружения элементов в структуре данных. Поскольку я новичок в XQuery, я все еще нахожу некоторые незнакомые концепции и очень благодарен за помощь от тех из вас, у кого есть многолетний опыт по сравнению с моими несколькими неделями с XQUery / Saxon.

Это часть анализа файла журнала, и я уже свел соответствующие данные в более компактную структуру XML (см. Ниже), которая хранится в последовательности в моем модуле XQuery. Теперь мне нужно передать эту последовательность функции, которая обнаруживает определенные события в данных. Моя структура следующая: -

<SEQUENCE><TIME>0.01</TIME><TAG>2100</TAG><FIELD>PRIMARY_MODE_CMD</FIELD><MODE>MODE1</MODE></SEQUENCE>
<SEQUENCE><TIME>0.57</TIME><TAG>2900</TAG><FIELD>PRIMARY_MODE_CNF</FIELD><MODE>MODE1</MODE></SEQUENCE>
<SEQUENCE><TIME>0.65</TIME><TAG>2900</TAG><FIELD>PRIMARY_MODE_CNF</FIELD><MODE>MODE1</MODE></SEQUENCE>
<SEQUENCE><TIME>1.29</TIME><TAG>2900</TAG><FIELD>PRIMARY_MODE_CNF</FIELD><MODE>MODE1</MODE></SEQUENCE>
<SEQUENCE><TIME>1.94</TIME><TAG>2900</TAG><FIELD>PRIMARY_MODE_CNF</FIELD><MODE>MODE1</MODE></SEQUENCE>
<SEQUENCE><TIME>2.57</TIME><TAG>2900</TAG><FIELD>PRIMARY_MODE_CNF</FIELD><MODE>MODE1</MODE></SEQUENCE>
<SEQUENCE><TIME>3.01</TIME><TAG>3800</TAG><FIELD>JAT_INITIALISE_CMD</FIELD><MODE>UPDATE_JAT_INITIALISE_PARAMS</MODE></SEQUENCE>
<SEQUENCE><TIME>3.03</TIME><TAG>2900</TAG><FIELD>PRIMARY_MODE_CNF</FIELD><MODE>MODE1</MODE></SEQUENCE>
<SEQUENCE><TIME>3.03</TIME><TAG>2900</TAG><FIELD>INVALID_CMD_CNF</FIELD><MODE>INVALID</MODE></SEQUENCE>

Функция XQuery (например, '* declare function local: analyse_case_1 ($ seq as element () ) as xs: boolean') должна принимать всю последовательность элементов (см. Выше) в качестве параметра и возвращать 'true 'если он обнаружит три события в строгой последовательности, а именно:

'2100 + PRIMARY_MODE_CMD + MODE1' - followed by:
'2900 + PRIMARY_MODE_CNF + MODE1' - followed by:
'3800 + JAT_INITIALISE_CMD + UPDATE_JAT_INITIALISE_PARAMS' - followed by:
'2900 + INVALID_CMD_CNF + INVALID'

Функция вернет false, если обнаружит, что этот порядок неверен, отсутствуют элементы и т. Д. В качестве второго требования она также должна возвращать false, если время между этими элементами больше 0,60.

Посмотрев на XQuery более подробно за последний день или около того, я считаю, что этого было бы легко достичь на скомпилированном языке, но по какой-то причине я не вижу немедленного способа использования XQuery. Я надеюсь, что кто-нибудь может указать мне правильное направление, пожалуйста?

С благодарностью.


person mactwixs    schedule 11.09.2012    source источник
comment
Строгая последовательность, значит ли это, что между ними не может быть никаких элементов?   -  person Fred Foo    schedule 11.09.2012
comment
Да, в журнале есть много дополнительных сообщений, которые можно игнорировать - нужно искать только выделенные сообщения.   -  person mactwixs    schedule 11.09.2012


Ответы (2)


У меня сложилось впечатление, что вам нужно найти сообщения, которые расположены последовательно, но не обязательно рядом. Этого можно добиться с помощью запроса формы

exists(
  SEQUENCE[TAG='2100' and FIELD='PRIMARY_MODE_CMD' and MODE='MODE1']
  /following-sibling::SEQUENCE[TAG='2900' and FIELD='PRIMARY_MODE_CNF' and MODE='MODE1']
  /following-sibling::SEQUENCE[TAG='3800' and FIELD='JAT_INITIALISE_CMD' and MODE='UPDATE_JAT_INITIALISE_PARAMS']
  /following-sibling::SEQUENCE[TAG='2900' and FIELD='INVALID_CMD_CNF' and MODE='INVALID'])

Вторая часть вопроса,

it should also return false if the time between these items is longer than 0.60

четко не указано. Вы имеете в виду время между первым и последним или время между любой парой событий? Вы можете справиться с этим, привязав переменные к выбранным элементам:

let $x := SEQUENCE[...],
    $y := $x/following-sibling[...],
    $z := $y/following-sibling[...][TIME lt $x/TIME + 0.6]
return exists($z)
person Michael Kay    schedule 11.09.2012
comment
Итак, правильно ли я думал, если бы использовал '/ following-sibling :: * [TAG =' 2900 'and FIELD =' PRIMARY_MODE_CNF 'and MODE =' MODE1 ']' после 'SEQUENCE [TAG =' 2100 'and FIELD = » PRIMARY_MODE_CMD 'и MODE =' MODE1 ']' дадут мне все PRIMARY_MODE_CNF, следующие за PRIMARY_MODE_CMD? Спасибо! - person mactwixs; 12.09.2012
comment
Нет, он предоставит вам только те, которые соответствуют запрошенным TAG и MODE. - person Michael Kay; 12.09.2012

Конструкция for $x at $pos in $seq - ваш друг:

for $x at $pos in $seq
  where $x/TAG eq "2100"
    and $x/FIELD eq "PRIMARY_MODE_CMD"
    and (some $y in subsequence($seq, $pos, count($seq))
           satisfies ($y/TAG eq "2900" and $y/FIELD eq "PRIMARY_MODE_CNF"))
  return $x

Это еще не полный запрос, но вы сможете начать отсюда. На практике я бы превратил это в несколько функций. Обратите внимание, что вызов subsequence внутри цикла означает, что этот запрос в худшем случае занимает O (n ²) времени.

person Fred Foo    schedule 11.09.2012
comment
Вау, спасибо за быстрый ответ. Да, в журнале есть много дополнительных сообщений, которые можно игнорировать - нужно искать только выделенные сообщения. Итак, используя метод, который вы описали, насколько я могу понять - первая половина запроса передает позицию первых 2100 PRIMARY_MODE_CMD последовательно в функцию «subsquence ()». Затем поиск продолжается с последней позиции ('$ pos') до тех пор, пока не будет найдено следующее совпадение? Нужно ли мне добавить еще, если после «возврата», если я хочу вернуть истину / ложь? - person mactwixs; 11.09.2012
comment
@mactwixs: используйте exists, чтобы получить логическое значение, как показывает Майкл Кей в своем ответе. - person Fred Foo; 11.09.2012
comment
Решение для следующих братьев и сестер предполагает, что показанная последовательность является последовательностью братьев и сестер. Я согласен, что, поразмыслив, из вопроса не совсем ясно, что это так. - person Michael Kay; 12.09.2012