Что является эквивалентом Tinkerpop для Neo4j match/join для значений свойств
У меня есть Neo4j
Cypher
запрос. Я пытаюсь понять, как сделать тот же запрос в Tinkerpop
/Gremlin
(не Neo4j
реализация).
start
f=node:node_auto_index('_Element:field OR _Element:dynamicField'),
t=node:node_auto_index(_Element = 'fieldType')
where
f.type=t.name
return
f, t
По сути, я получаю два типа узлов (метки / типы / все что угодно) и пытаюсь найти, где одно указывает на другое через совпадение значения свойства. Затем я создам реальные отношения, используя результаты.
График не очень большой, до нескольких тысяч узлов.
1 ответ
Как и во всем, есть много способов приблизиться к этому. Поскольку у вас есть небольшой набор данных, я не думаю, что это будет проблемой для поиска g.V
в трубопроводе Гремлин. Чтобы смоделировать вашу проблему, я создал свою собственную: используя игрушечный график, добавьте sameFirstLetter
край любой вершины, которая имела lang
свойство любой вершины, которая имела age
собственности и где первая буква их соответствующих name
свойства были одинаковыми. В этом случае следует добавить две вершины, от 5 до 4 и от 3 до 4.
gremlin> g = TinkerGraphFactory.createTinkerGraph()
==>tinkergraph[vertices:6 edges:6]
gremlin> g.V.has('lang').transform{v->[v,g.V.has('age').filter{it.name.startsWith(v.lang[0])}.toList()]}.sideEffect{edgeList->edgeList[1].each{it.each{edgeList[0].addEdge('sameFirstLetter',it)}}}
==>[v[3], [v[4]]]
==>[v[5], [v[4]]]
gremlin> g.E
==>e[1][5-sameFirstLetter->4]
==>e[10][4-created->5]
==>e[0][3-sameFirstLetter->4]
==>e[7][1-knows->2]
==>e[9][1-created->3]
==>e[8][1-knows->4]
==>e[11][4-created->3]
==>e[12][6-created->3]
Этот код состоит из двух частей. Первый создает список совпадений, а второй создает ребро. Вот часть, которая получает список смежности:
g.V.has('lang').transform{v->[v,g.V.has('age').filter{it.name.startsWith(v.lang[0])}.toList()]}
Приведенный выше код в основном говорит, захватить все вершины, которые имеют lang
свойство (обратите внимание, что это использование has
является частью последней версии Gremlin - скоро будет выпущен 2.4.0. До 2.4.0 вы могли сделать .hasNot('lang',null)
или что-то подобное), а затем преобразовать их в список, где первый элемент в списке является lang
вершина и второй элемент в списке - это список вершин графа, соответствующих первой букве name
с первой буквой lang
(в этом случае письмо j
для обоих lang
вершины).
.sideEffect{edgeList->edgeList[1].each{it.each{edgeList[0].addEdge('sameFirstLetter',it)}}}
Приведенный выше побочный эффект обрабатывает этот вывод... список смежности:
==>[v[3], [v[4]]]
==>[v[5], [v[4]]]
Эта операция может быть выполнена в виде отдельной строки кода (не все Gremlin должны быть записаны в одну строку... как бы это ни было удовлетворительно). Вы можете просто сохранить список смежности в переменной, а затем обработать его, чтобы создать ребра. В любом случае я решил использовать sideEffect
здесь, где я зацикливаю список списков, создавая рёбра.
В качестве альтернативы, вы также можете сделать два прохода по набору данных, создав индекс в памяти, основанный на значении свойства, а затем использовать его в качестве поиска для построения списка смежности. Таким образом, вы только перенесете два прохода через список вершин:
gremlin> m=g.V.groupBy{it.name[0]}{it}.cap.next()
==>v=[v[2]]
==>r=[v[5]]
==>p=[v[6]]
==>l=[v[3]]
==>m=[v[1]]
==>j=[v[4]]
gremlin> g.V.has('lang').transform{[it,m[it.lang[0]]]}
==>[v[3], [v[4]]]
==>[v[5], [v[4]]]
Это приведет вас к тому же списку смежности, что и в предыдущем примере. Создание края с помощью списка смежности все еще выполняется, как отмечалось ранее.