Как вернуть несколько узлов, используя кратчайший путь? - PullRequest
0 голосов
/ 31 января 2020

Я пытаюсь воссоздать это в C#:

    MATCH p=shortestPath((bacon:Person {name:"Kevin Bacon"})-[*]-(meg:Person {name:"Meg Ryan"}))
    RETURN p

Но все найденные мной примеры, использующие кратчайший путь, возвращают только список узлов того же типа. В этом примере мне нужно вернуть узлы People и Movies. Итак, это начинается примерно так:

    var shortestPath = graphClient.Cypher
            .OptionalMatch("p = shortestPath((bacon: Person )-[*] - (meg: Person ) )")
            .Where((Person bacon) => bacon.name == "Kevin Bacon ")
            .AndWhere((Person meg) => meg.name == "Meg Ryan")
            .Return(?)
            .Results;

Что мне написать вместо знака вопроса?

График выглядит так: enter image description here

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

1 Ответ

1 голос
/ 03 февраля 2020

Хороший вопрос - и трудно разобраться, я думаю, что у меня есть - хотя - это, вероятно, не самый производительный.

Как вы говорите, проблема заключается в нескольких типах - поэтому давайте настроим все, я использую метод расширения, чтобы сделать этот код более привлекательным:

public static class Extensions
{
    public static T ToObject<T>(this string value)
    {
        //deserialize into a 'Node' first
        var node = JsonConvert.DeserializeObject<Node>(value);

        //then take the 'data' from that and 'ToObject' to the correct thing.
        return ((JObject) node.data).ToObject<T>();
    }

    private class Node{
        public object data {get;set;}
    }
}

The * Метод 1006 * - это то, что мы будем использовать для преобразования нашего вывода в объекты.

У меня есть стандартный набор POCO для представления данных (хотя и с неправильными соглашениями об именах для свойств):

public class Movie {
    public string title {get;set;}
    public string tagline {get;set;}
}

public class Person {
    public string name {get;set;}
    public int born {get;set;}
}

public class RolesRel {
    public IEnumerable<string> roles {get;set;}
}

ОК - теперь мы готовы к go. Я изменил Return, чтобы он выглядел так:

var shortestPath = graphClient.Cypher
     .OptionalMatch("p = shortestPath((bacon: Person)-[*]-(meg: Person ) )")
     .Where((Person bacon) => bacon.name == "Kevin Bacon")
     .AndWhere((Person meg) => meg.name == "Meg Ryan")
     .Return(p => new {
        Nodes = Return.As<IEnumerable<string>>("nodes(p)"),
        Relationships = Return.As<IEnumerable<RolesRel>>("rels(p)")
     });

string - это единственная универсальная опция, которую мы получили для десериализации нескольких типов узлов. В этом сценарии, поскольку отношения все одинаковы, мы все хорошо на этом фронте просто используем POCO - но если бы они не были, вы бы в конечном итоге сделали то же, что мы делаем для узлов для них.

Далее я просматриваю результаты:


foreach (var result in shortestPath.Results)
{
    foreach (var node in result.Nodes)
    {
        if(node.Contains("name"))
            Console.WriteLine(node.ToObject<Person>().name);
        else if(node.Contains("title"))
            Console.WriteLine(node.ToObject<Movie>().title);
        else {
            Console.WriteLine("Unknown Node Type: " + node);
        }
    }
}

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

Очевидно - я просто выводлю на экран - но у вас будет доступ к самому объекту.

...