2015-09-11 6 views
1

У меня есть база данных диаграммы OrientDB с узлами, соединенными последовательно со ссылкой типа NEXT. (В моих данных несколько отдельных рядов, и ни один узел не имеет более одной входящей и одной исходящей ссылки «NEXT»). Все узлы имеют свойство «имя». Я хотел бы найти все последовательности имени, которые происходят при прохождении путей от начала до конца.агрегирование данных пути в orientdb

I.e. чтобы получить одну последовательность имен, начните с узла, у которого нет входящей NEXT-ссылки, следуйте по ссылкам NEXT, пока не достигнете узла без исходящих «NEXT» ссылок и соберите в списке все имена узлов, которые у вас есть прошло.

например. суб-граф формы (Bob)-[NEXT]->(Sharon)-[NEXT]->(Carl) должен дать список ["Bob", "Sharon", "Carl"]

Для уточнения, здесь Cypher (Neo4j) запрос, который получает мне все возможные списки.

match (start) -[:NEXT*]-> (end), 
    p = shortestPath(start-[:NEXT*]-> end) 
    where not()-[:NEXT]->(start) and not (end)-[:NEXT]->() 
    return extract(s in nodes(p) | s.name) as path 

Однако, мне нужно сделать это в OrientDB, который не использует Cypher.

Я хотел бы знать, возможно ли это в OrientDB, и если да, то проще ли это на языке SQL или Gremlin.

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

UPDATE

Я создал некоторые данные примера здесь, чтобы соответствовать заявление моего первоначального вопроса.

create database plocal:people 
create class Person extends V 
create property Person.name string 
create property Person.age float 
create property Person.ident integer 

insert into Person(name,age,ident) VALUES ("Bob", 30.5, 1) 
insert into Person(name,age,ident) VALUES ("Bob", 30.5, 2) 
insert into Person(name,age,ident) VALUES ("Carol", 20.3, 3) 
insert into Person(name,age,ident) VALUES ("Carol", 19, 4) 
insert into Person(name,age,ident) VALUES ("Laura", 75, 5) 
insert into Person(name,age,ident) VALUES ("Laura", 60.5, 6) 
insert into Person(name,age,ident) VALUES ("Laura", 46, 7) 
insert into Person(name,age,ident) VALUES ("Mike", 16.3, 8) 
insert into Person(name,age,ident) VALUES ("David", 86, 9) 
insert into Person(name,age,ident) VALUES ("Alice", 5, 10) 
insert into Person(name,age,ident) VALUES ("Nigel", 69, 11) 
insert into Person(name,age,ident) VALUES ("Carol", 60, 12) 
insert into Person(name,age,ident) VALUES ("Mike", 16.3, 13) 
insert into Person(name,age,ident) VALUES ("Alice", 5, 14) 
insert into Person(name,age,ident) VALUES ("Mike", 16.3, 15) 

create class NEXT extends E 

create edge NEXT from (select from Person where ident = 1) to (select from Person where ident = 3) 
create edge NEXT from (select from Person where ident = 2) to (select from Person where ident = 4) 
create edge NEXT from (select from Person where ident = 8) to (select from Person where ident = 12) 
create edge NEXT from (select from Person where ident = 5) to (select from Person where ident = 15) 
create edge NEXT from (select from Person where ident = 15) to (select from Person where ident = 14) 
create edge NEXT from (select from Person where ident = 7) to (select from Person where ident = 13) 
create edge NEXT from (select from Person where ident = 13) to (select from Person where ident = 10) 

Это должно дать мне следующий окончательный результат

  • 2 из ["Bob", "Carol"]
  • 2 из ["Laura", "Mike", "Alice"]
  • 1 из ["Laura"]
  • 1 из ["Mike", "Carol"]
  • 1 из ["David"]
  • 1 из ["Nigel"]

Вот что я получаю, используя предложения neRok

Во-первых, выбрать все начальные узлы - это работает, как ожидалось

orientdb {db=people}> select from Person where in_NEXT is null 

----+------+------+-----+----+-----+-------- 
# |@RID |@CLASS|name |age |ident|out_NEXT 
----+------+------+-----+----+-----+-------- 
0 |#11:0 |Person|Bob |30.5|1 |[#12:0] 
1 |#11:1 |Person|Bob |30.5|2 |[#12:1] 
2 |#11:4 |Person|Laura|75.0|5 |[#12:3] 
3 |#11:5 |Person|Laura|60.5|6 |null 
4 |#11:6 |Person|Laura|46.0|7 |[#12:5] 
5 |#11:7 |Person|Mike |16.3|8 |[#12:2] 
6 |#11:8 |Person|David|86.0|9 |null 
7 |#11:10|Person|Nigel|69.0|11 |null 
----+------+------+-----+----+-----+-------- 

Теперь, если я пытаюсь получить массивы имен, полученные путем прохождения от этих узлов

select $series.name from (select from Person where in_NEXT is null) let $series = (traverse out('NEXT') from $current) 

----+------+------- 
# |@CLASS|$series 
----+------+------- 
0 |null |[0] 
1 |null |[0] 
2 |null |[0] 
3 |null |[0] 
4 |null |[0] 
5 |null |[0] 
6 |null |[0] 
7 |null |[0] 
----+------+-------  

Я думаю, это означает, что он не получает результатов от обхода или не может создать массив имен?

Заключительный шаг агрегации обрабатывает все эти строки, как то же самое:

orientdb {db=people}> select series, sum(1) as number from (select $series.name as series from (select from Person where in_NEXT is null) let $series = (traverse out('NEXT') from $current)) group by series 

----+------+------+------ 
# |@CLASS|series|number 
----+------+------+------ 
0 |null |[0] |8 
----+------+------+------ 

, так что я не получаю результат я хотел.

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

Вот пример обхода с одного узла: orientdb {дб = человек}> траверсировать из ('Вперед') из (выберите из Person, где идент = 7)

----+------+------+-----+----+-----+--------+------- 
# |@RID |@CLASS|name |age |ident|out_NEXT|in_NEXT 
----+------+------+-----+----+-----+--------+------- 
0 |#11:6 |Person|Laura|46.0|7 |[#12:5] |null 
1 |#11:12|Person|Mike |16.3|13 |[#12:6] |[#12:5] 
2 |#11:9 |Person|Alice|5.0 |10 |null |[#12:6] 
----+------+------+-----+----+-----+--------+------- 
+0

глупый вопрос: Почему бы просто не использовать Neo4j, если вы уже решили проблему там? –

+0

Не глупый вопрос, всегда стоит проверить :) По причинам, которые я не хочу здесь описывать, я не могу использовать Neo4j для этого проекта, но вместо этого должен использовать OrientDB. Очевидно, для меня в этом конкретном случае Neo4j будет более удобным, но он недоступен. – arbie

+0

@arbie сообщите мне, могу ли я вообще помочь (возможно, это проблема лицензирования, которую можно смягчить и т. Д.). -орький мальчик. e-mail: . на neotechnology.com –

ответ

0

Прежде всего, вам нужно запрос для получения узлов без входящих ребер. Этот запрос будет использоваться в качестве подзапроса. Руководство orientdb предлагает что-то вроде select from Nodes where in('NEXT').size() = 0, но следующее мне кажется немного быстрее (YMMV) select from Nodes where in_NEXT is null.

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

select $series.name from (
    select from Nodes where in_NEXT is null 
) 
let $series = (traverse out('NEXT') from $current) 

Этот запрос возвращает строки с данными , как вы хотели.

Теперь вам немного о том, как считать каждую серию. Я всегда пробиваю себе путь, когда сталкиваюсь с уникальными/разными и считает (так что это может быть не очень хороший метод), но, похоже, работает;

select series, sum(1) as number from (
    select $series.name as series from (
    select from Nodes where in_NEXT is null 
) 
    let $series = (traverse out('NEXT') from $current) 
) 
group by series 

Таким образом, мы обернули предыдущий запрос в другом запросе, какие группы по серии, а затем получает подсчет каждой строки.

На боковой ноте это кажется «дорогим» запросом. Возможно, вы можете создать свою базу данных более эффективно? Однако это был бы другой вопрос/дискуссия.


Обновление для решения проблемы с обновлением; Используя вашу базу данных, все мои запросы работают в веб-приложении студии. Однако в консоли есть некоторые «причуды». Первый запрос дает мне следующее в консоли;

orientdb {db=stackpeople}> select $series.name from (select from Person where in_NEXT is null) let $series = (traverse out('NEXT') from $current) 

----+------+------- 
# |@CLASS|$series 
----+------+------- 
0 |null |[2] 
1 |null |[2] 
2 |null |[3] 
3 |null |[1] 
4 |null |[3] 
5 |null |[2] 
6 |null |[1] 
7 |null |[1] 
----+------+------- 

Я не знаю, почему ваши результаты показывают каждую строку $ рядов как [0]. Возможно, вы не запрашиваете правильные поля (т. Е. Вы не используете демо-базу данных сверху). Мое другое предположение, что проблема в используемой версии OrientDB - я использую 2.1-rc6.

Нулевой класс правильный, поскольку это запроектированный запрос, а не запись. Это может быть запись, изменив начало запроса на select *, $series.name from ....

По какой-то причине серия $ не расширяется в консоли, но показывает количество записей, которые содержат серии $ ($ series должен быть списком). Обычно я не использую консоль, поэтому я не знаю, является ли это предполагаемым результатом или ошибкой (я думаю, это так, как показано в списках).Я нашел способ показать имена, но со следующим запросом;

orientdb {db=stackpeople}> select *, $series.name.asString() as names from (select from Person where in_NEXT is null) let $series = (traverse out('NEXT') from $current) 

----+------+------+-----+----+-----+--------+-------------------- 
# |@RID |@CLASS|name |age |ident|out_NEXT|names 
----+------+------+-----+----+-----+--------+-------------------- 
0 |#11:0 |Person|Bob |30.5|1 |[size=1]|[Bob, Carol] 
1 |#11:1 |Person|Bob |30.5|2 |[size=1]|[Bob, Carol] 
2 |#11:4 |Person|Laura|75.0|5 |[size=1]|[Laura, Mike, Alice] 
3 |#11:5 |Person|Laura|60.5|6 |null |[Laura] 
4 |#11:6 |Person|Laura|46.0|7 |[size=1]|[Laura, Mike, Alice] 
5 |#11:7 |Person|Mike |16.3|8 |[size=1]|[Mike, Carol] 
6 |#11:8 |Person|David|86.0|9 |null |[David] 
7 |#11:10|Person|Nigel|69.0|11 |null |[Nigel] 
----+------+------+-----+----+-----+--------+-------------------- 

Что касается последнего запроса (количество имен), мой запрос дает;

orientdb {db=stackpeople}> select series, sum(1) as number from (select $series.name as series from (select from Person where in_NEXT is null) let $series = (traverse out('NEXT') from $current)) group by series 

----+------+------+------ 
# |@CLASS|series|number 
----+------+------+------ 
0 |null |[2] |2 
1 |null |[3] |2 
2 |null |[1] |1 
3 |null |[2] |1 
4 |null |[1] |1 
5 |null |[1] |1 
----+------+------+------ 

Какая правильная снова (хотя серия показана как результат). Это может быть изменено следующим:

orientdb {db=stackpeople}> select names.asString(), sum(1) as number from (select $series.name as names from (select from Person where in_NEXT is null) let $series = (traverse out('NEXT') from $current)) group by names 

----+------+--------------------+------ 
# |@CLASS|names    |number 
----+------+--------------------+------ 
0 |null |[Bob, Carol]  |2 
1 |null |[Laura, Mike, Alice]|2 
2 |null |[Laura]    |1 
3 |null |[Mike, Carol]  |1 
4 |null |[David]    |1 
5 |null |[Nigel]    |1 
----+------+--------------------+------ 

Обратите внимание, что изменение списка в строку означает, что вам нужно будет разделить эту строку в любую программу/код получает результаты запроса, чтобы знать имя каждого. Таким образом, вероятно, лучше не менять его на строку, тогда запрос действительно вернет список.

+0

Большое спасибо за ваш ответ - у меня есть длинный путь к пониманию, как это сделать. Я согласен, что модель данных кажется немного странной - на самом деле это не точная, которую я использовал, но я попытался дать простую модель данных с достаточной информацией, чтобы объяснить запрос, который я хотел выполнить. Однако я не могу заставить это работать. Вы ожидаете, что $ series станет набором узлов и $ series.name, чтобы вернуть список имен узлов в этой коллекции? – arbie

+0

Yer, в этом случае это будет коллекция вершин, узлов. – neRok

+0

Я создал некоторые образцы данных в соответствии с моим исходным вопросом и опробовал предложенные вами запросы (я описал результаты в редактировании исходного вопроса). Боюсь, у меня все еще возникают проблемы с получением результатов, которые я хотел. Если бы у вас появился другой взгляд, который бы действительно помог. – arbie

Смежные вопросы