动态Cypher搜索查询

时间:2014-11-26 23:29:51

标签: neo4jclient

我知道这听起来可能是胡说八道,但我会尽力解释我所面对的neo4jClient问题。

我开发了Social TaskManagment软件。对于服务器端代码和数据存储,我选择使用neo4j(neo4jClient)和C#。

在我们的软件中想象一个用户:(mhs)发布的任务“@ somebody请帮助我#Neo4j #cypher”任务将装饰一些花哨的角色,包括(@#+ /)obove post将在neo4j中保存为如下图:

(post:Post {Text : @somebody please help me on #Neo4j})-[Has_HashTag]-(neo4j:HashTag)
(post:Post)-[Has_HashTag]-(Cypher: HashTag)
(post:Post)-[Has_Author)-[mhs:User]
(post:Post)-[Has_MentionedUser)-[Somebody:User]

现在想象用户@mhs正在尝试搜索#Neo4j的HashTag并向@somebody提及的帖子

这里我正在构建(手工制作)Cypher查询,其中包括Cypher中的2个参数参数以及一些花哨的C#代码,这些代码导致了Cypher查询:

MATCH (nodes)-[r]-(post:Post),
(post:Post)-[:HAS_MentionedUsers]->(assignee1307989068:User),
(nodes)-[r]-(post:Post)-[:HAS_HashTags]->(Hashtag1482870844:HashTag)
WHERE (assignee1307989068.UserName = "somebody") AND (Hashtag1482870844.Value = "neo4j")
RETURN post AS Post, Collect(nodes) as nodes
ORDER BY post.creationDate

上面的cypher将返回一个帖子,其中只包含帖子中未包含在Where子句中的所有节点。 我的问题是如何包含与Targeted(post)相关的所有节点,而不将它们包含在cypher的Return部分中。像return(*)。

其他问题是如何将结果集反序列化为C#而不知道它可能具有什么形状。

我正在制作上述Cypher的搜索方法是休闲的:

public List<PostNode> Search(string searchterm)
    {
        List<string> where = new List<string>();
        var tokenizedstring = searchterm.Split(' ');
        var querystring = new StringBuilder();
        var relatedNodes = new List<string>();

        var q = new CypherFluentQuery(_graphClient) as ICypherFluentQuery;

        foreach (var t in tokenizedstring)
        {
            _commandService.BuildPostQueystring(t, ref querystring, ref where, ref relatedNodes);
        }
        if (querystring[querystring.Length - 1] == ',')
                querystring = querystring.Remove(querystring.Length - 1, 1);

            q = q.Match(querystring.ToString());

            int i = 1;

            if (where.Count > 0)
                q = q.Where(where[0]);

            while (i < where.Count)
            {
                q = q.AndWhere(where[i]);
                i++;

            }

            var rq = q.Return(
                (post, nodes) => new PostNode
                {
                    Post = post.As<Node<string>>(),
                    Nodes = nodes.CollectAs<string>()
                })
                .OrderBy("post.creationDate");


        var results = rq.Results.ToList();

        //foreach (var result in results)
        //{

        //    //dynamic p = JsonConvert.DeserializeObject<dynamic>(result.Post.Data);
        //    //dynamic d = JsonConvert.DeserializeObject<dynamic>(result.Nodes.Data);

        //}

        return results;
    }
}

//Some Helper Class just to cast the result.
    public class PostNode 
    {
        public Node<string> Post { get; set; }
        public IEnumerable<Node<string>> Nodes { get; set; }
    }

但是您可能已经注意到它没有通过Cypher Query中的Where子句包含在搜索词中的节点。 我真的在这里停留了一段时间,因为我无法为此提供任何合适的解决方案。所以你的帮助可以为我节省很多。 可能是我完全走错了路,所以请以任何你能想到的方式提供帮助。

1 个答案:

答案 0 :(得分:3)

似乎正在配置UNKNOWN相关节点的列表,因此其中一个:

情景A

这些相关节点究竟是什么并不重要,我只想要它们。

问题:检索那些未知但相关的节点的意图是什么?通过回答这个机会,这个问题可以很好地改进。

情景B

这些未知的相关节点实际上是已知的!它只是在查询执行时并不完全知道,但是在C#代码的某个地方,我们会有这样的事情

if (nodes.Any(_ => _ is HashTag) {...}

问题:

这种行为需要知道类型。即使使用反射或C#动态的东西,要求仍然存在,因为Neo4jClient无法将来自Neo4j的一包JSON数据关联到任何本地类型。当Neo4jClient以某种方式通过线路接收大量数据时,它应该知道您更喜欢用什么类型来表示。这就是查询总是这样的原因:

Return((a, p) => new
{
    Author = a.As<Author>(), //we expect node content to be represented as Author
    Post = p.As<Post>()
})

Neo4jClient 不会在Neo4j数据库中保留C#类型。这样做本来是很讨厌的。然而,背后的想法是你不应该发现自己迫不及待,如果你这样做,那么我会建议在其他地方寻找问题,即为什么你会依靠你的客户端库为你描述你的域名?