Свернуть два запроса в один

У меня есть следующие объекты в моей базе данных Neo4J (с использованием версии 2.0).

Target
Library
Function

Это отношения между каждым.

function[:used_in]->target
function[:included_in]->library
library[:part_of]->target

Моя конечная цель — построить дерево на C#, которое позволит мне выразить сопоставление между функциями, которые используются в Target, но со способом связать их обратно с их исходной библиотекой. В дереве библиотека будет представлена ​​как родительский узел функции.

Другими словами, предположим, что библиотека предоставляет 10 различных функций, но только 5 из них используются (используются_в) данной целью. Меня интересуют только эти 5, а не остальные. Для каждой функции я хочу иметь возможность быстро (в моем дереве) добраться до библиотеки, которая «включает» данную функцию. У меня есть коллекция таргетов и я понимаю, что мне, скорее всего, придется выдавать отдельный запрос для каждого таргета. Моя цель - избежать выдачи нескольких запросов для каждой цели/библиотеки/функции.

Учитывая отношения, которые я описал, возможно ли построить запрос Cypher, который вернет мне интересующие узлы?

Вот запрос Cypher, который вернет все функции для данной цели.

MATCH (function:Function)-[:used_in]->(target:Target)
WHERE (target.Name = "target.exe")
RETURN function

Вот запрос Cypher, который вернет библиотеку для данной функции.

MATCH (function:Function)-[:included_in]->(library:Library)
WHERE (function.Name = "foo")
RETURN library

Мне интересно посмотреть, можно ли это объединить в один запрос. В моем текущем сценарии мне нужно будет выполнить второй запрос для каждой функции. Я надеюсь, что мои отношения достаточно оптимальны, чтобы позволить мне сократить количество запросов, которые мне нужно сделать.

Я использую Neo4JClient — если кто-то поможет предоставить запрос Cypher, я надеюсь, что смогу перевести его в Neo4JClient. Если кто-то пойдет еще дальше и даст мне код C#, тем лучше, но, пожалуйста, помогите мне понять стоящий за ним шифр.

Вот Cypher для создания базы данных:

CREATE (t:Target { Name: 'Target.exe' })
CREATE (t:Target { Name: 'Target2.exe' })
CREATE (t:Target { Name: 'Target3.exe' })
CREATE (l:Library { Name: 'Library.lib', Path: 'i386' })
CREATE (l:Library { Name: 'Library.lib', Path: 'amd64' })
CREATE (l:Library { Name: 'Library2.lib', Path: 'amd64' })
CREATE (f:Function { Name: 'FunctionA' })
CREATE (f:Function { Name: 'FunctionB' })
CREATE (f:Function { Name: 'FunctionC' })
CREATE (f:Function { Name: 'FunctionZ' })

MATCH (f:Function),(l:Library) WHERE (f.Name = "FunctionA") AND (l.Name = "Library.lib") AND (l.Path = "amd64") CREATE f-[:included_in]->l
MATCH (f:Function),(l:Library) WHERE (f.Name = "FunctionB") AND (l.Name = "Library.lib") AND (l.Path = "amd64") CREATE f-[:included_in]->l
MATCH (f:Function),(l:Library) WHERE (f.Name = "FunctionC") AND (l.Name = "Library2.lib") AND (l.Path = "amd64") CREATE f-[:included_in]->l
MATCH (f:Function),(l:Library) WHERE (f.Name = "FunctionZ") AND (l.Name = "Library.lib") AND (l.Path = "i386") CREATE f-[:included_in]->l
MATCH (f:Function),(l:Library) WHERE (f.Name = "FunctionZ") AND (l.Name = "Library.lib") AND (l.Path = "amd64") CREATE f-[:included_in]->l

MATCH (f:Function),(t:Target) WHERE (f.Name = "FunctionA") AND (t.Name = "Target.exe") CREATE f-[:used_in]->t
MATCH (f:Function),(t:Target) WHERE (f.Name = "FunctionB") AND (t.Name = "Target.exe") CREATE f-[:used_in]->t
MATCH (f:Function),(t:Target) WHERE (f.Name = "FunctionC") AND (t.Name = "Target2.exe") CREATE f-[:used_in]->t
MATCH (f:Function),(t:Target) WHERE (f.Name = "FunctionZ") AND (t.Name = "Target3.exe") CREATE f-[:used_in]->t

MATCH (l:Library),(t:Target) WHERE (l.Name = "Library.lib") AND (l.Path ="amd64") AND (t.Name = "Target.exe") CREATE l-[:part_of]->t
MATCH (l:Library),(t:Target) WHERE (l.Name = "Library2.lib") AND (l.Path ="amd64") AND (t.Name = "Target2.exe") CREATE l-[:part_of]->t
MATCH (l:Library),(t:Target) WHERE (l.Name = "Library.lib") AND (l.Path ="i386") AND (t.Name = "Target3.exe") CREATE l-[:part_of]->t

Для тех, кто заинтересован, вот код Neo4Client, который я использовал на основе запроса Cypher, предоставленного Уэсом.

var query = graphClient.Cypher
.Match("(function:Function)-[:used_in]->(target:Target),(function:Function)-[:included_in]->(library:Library)")
.Where((Target target) => target.Name == sourceTarget.Name)
.AndWhere((Target target) => target.Path == sourceTarget.Path)
.AndWhere((Target target) => target.PEType == sourceTarget.PEType)
.AndWhere((Target target) => target.FileArch == sourceTarget.FileArch)
.AndWhere((Library library) => library.Name == sourceLibrary.Name)
.AndWhere((Library library) => library.Path == sourceLibrary.Path)
.AndWhere((Library library) => library.PEType == sourceLibrary.PEType)
.AndWhere((Library library) => library.FileArch == sourceLibrary.FileArch)
.Return((function) => new
{
    Functions = function.CollectAs<Function>()
})
.Results
.Select(result => new FunctionCollection()
{
    Collection = result.Functions.Select(a => a.Data).ToList()
});

person Raymond Parsons    schedule 05.01.2014    source источник
comment
было бы здорово, если бы вы могли привести пример графика либо с операторами создания, либо на console.neo4j.org.   -  person Eve Freeman    schedule 05.01.2014
comment
Спасибо, Уэс. Я постараюсь составить минимальный набор утверждений и предоставить их. Есть ли способ вставить сразу несколько операторов Cypher в консоль? Я прибегнул к копированию/вставке, и это было болезненно, когда я понял, что мне нужно начать сначала.   -  person Raymond Parsons    schedule 05.01.2014
comment
Вы должны делать по одному в консоли. :(   -  person Eve Freeman    schedule 05.01.2014
comment
Я добавил заявления выше. Я не мог поделиться ссылкой, потому что это не позволило бы мне добавить начальные операторы Cypher. Я думаю, вы всегда можете просто делать их 1 на 1, но это болезненно. Поскольку приведенный ниже запрос работает, сейчас в нем нет необходимости, но он добавлен для полноты картины.   -  person Raymond Parsons    schedule 05.01.2014


Ответы (1)


Кажется, что это слишком просто, но так ли это просто? Пожалуйста, предоставьте больше информации, если нет.

MATCH (function:Function)-[:used_in]->(target:Target),
      (function:Function)-[:included_in]->(library:Library)
WHERE (target.Name = "target.exe")
RETURN function, library
person Eve Freeman    schedule 05.01.2014
comment
Спасибо, Уэс. Когда я выполнил ваш запрос к своим реальным данным, он выдал мне две библиотеки с тем же именем, но с другим свойством пути. Мне нужно подтвердить, что данные вставляются в базу данных правильно, так как я не уверен, является ли это ошибкой в ​​​​моем коде вставки или нет. Когда я попытался смоделировать сценарий с помощью консоли с поддельными данными, я не воспроизвел проблему. Я отвечу после того, как все перепроверю. Спасибо еще раз. - person Raymond Parsons; 05.01.2014
comment
Похоже, это работает, хотя теперь я понимаю, откуда взялось мое замешательство. Мне нужно будет изменить узлы Library и Target с дополнительным свойством, которое позволит мне фильтровать определенный атрибут во время запроса. Я очень ценю помощь. Я отмечу это как ответ и попытаюсь понять, как перевести это на С#. Если вы можете помочь, это было бы здорово. - person Raymond Parsons; 05.01.2014
comment
Вы потенциально можете использовать свойства на других узлах для фильтрации — можете ли вы описать, что вы имеете в виду? Может быть, было бы хорошо поставить это в новый вопрос. - person Eve Freeman; 05.01.2014
comment
Спасибо, Уэс. У меня это работает, и это намного лучше, чем то, что я использовал раньше. На составление дерева у меня уходит с 6 минут до менее минуты. Я подтянул объекты, чтобы они имели более четкие свойства, а затем добился того, чтобы объекты были связаны через свойство. Моя проблема в том, что я не мог быть достаточно конкретным в своих запросах, и это приводило к дублированию. Предоставленный вами шифр отлично работает. - person Raymond Parsons; 06.01.2014
comment
В C# ключевая часть, которая вам нужна, — это просто расширить вызов Return дополнительным столбцом: Return((function, library) => new { Function = function.As‹Function›(), Library = library.As‹Library› () }) - person Tatham Oddie; 06.01.2014
comment
Если вы не можете правильно преобразовать Cypher в C#, откройте его как новый вопрос. Здесь невозможно отформатировать что-либо полезное в комментариях. - person Tatham Oddie; 06.01.2014