Neo4j:不知道如何将图形映射到 Spring Data bean

Posted

技术标签:

【中文标题】Neo4j:不知道如何将图形映射到 Spring Data bean【英文标题】:Neo4j: Don't know how to map graph to Spring Data bean 【发布时间】:2019-02-24 00:15:52 【问题描述】:

我正在编写一个应用程序来捕获其他应用程序的配置属性。 Config 是我的主要域对象。 Config 对象之间存在层次关系(一个Config [:OVERRIDES] 另一个Config)。因此,给定一个最底层的Config,我需要一直向上到最顶层的Config,并沿途收集Config 对象的所有属性,将它们合并为一个最终的Config。但我不知道如何使用 Spring Data 来做到这一点。

这是 2 个Config 对象的架构:

CREATE (c1:Config name:'ConfigParent');
SET c2.docker_tag='1.0.0';
SET c2.mem_limit='1gb';

MATCH (c1:Config name: 'ConfigParent') 
CREATE (c2:Config name:'ConfigChild')-[:OVERRIDES]->(c1)
SET c2.docker_tag='1.0.1';

ConfigChild 属性需要与ConfigParent 合并,ConfigParent 中的任何重复属性都将被覆盖。所以我的最后一组属性应该是:

name='ConfigMerged'  //I don't know what this name would be?
docker_tag='1.0.1'
mem_limit='1gb'

Config 中可以有任何键/值对,因此它们不能按名称返回。我想出了这个 CQL,我认为它可以满足我的需求:

MATCH p = SHORTESTPATH((c2:Config)<-[:OVERRIDES*]-(c1:Config)) 
WHERE c1.name = 'ConfigChild' and not (c2)-[:OVERRIDES]->() 
UNWIND NODES(p) as props return PROPERTIES(props);

JSON 响应如下所示:

[
  
    "keys": [
      "properties(props)"
    ],
    "length": 1,
    "_fields": [
      
        "name": "ConfigParent",
        "docker_tag": "1.0.0",
        "mem_limit": "1gb"
      
    ],
    "_fieldLookup": 
      "properties(props)": 0
    
  ,
  
    "keys": [
      "properties(props)"
    ],
    "length": 1,
    "_fields": [
      
        "name": "ConfigChild",
        "docker_tag": "1.0.1"
      
    ],
    "_fieldLookup": 
      "properties(props)": 0
    
  
]

问题是,我不知道如何将其映射到 POJO。我需要Config 域对象还是Properties 域对象?这是实现我目标的最佳 CQL 吗?

更新:我为Config 提出了一个带注释的 POJO。但是当我尝试用代码返回它时,properties 总是空的,还有parentConfig

@NodeEntity
public class Config 

    @Id 
    @GeneratedValue 
    private Long id;

    @Relationship(type = "OVERRIDES")
    private Config parentConfig;

    @Properties(allowCast=true)
    private Map<String, String> properties;

    ....

这是我正在测试的基本查询,只是为了看看我是否可以映射到 POJO:

 @Query("MATCH (c1:Config) RETURN c1;")
 List<Config> findConfigAny(@Param("configName") String configName);

【问题讨论】:

你用 spring-data-neo4j 标记了这个;所以你不是已经有一个代表这个的带有spring注释的pojo吗?然后只需将路径从没有父节点的配置节点返回到没有子节点的配置节点。除非您需要折叠密码中的值,否则为什么您的 neo4j 数据不能反映您正在使用的实际对象? 不,我不知道。我想不出合适的pojo。这就是我问问题的原因。 我没有专门用过spring-data-neo4j,但是spring-data系列的重点是能够轻松访问/保存你的数据,而不需要知道数据库长什么样。您可能应该更多地阅读 spring-data-neo4j,并首先创建您的 POJO。如果您不是 Neo4j 中数据的所有者,我不确定您将如何在其上使用 spring-data-neo4j。如果 spring-data-neo4j 对答案不重要,并且您将接受 Cypher 返回合并的地图而不是 POJO,那么我可以提供帮助。 (或按顺序排列的设置列表,如果您需要保留该信息) 请看我的更新和赏金..., 您能分享您的find() 代码吗?带注释的 POJO 看起来是正确的。另外,我希望查找失败会返回 null,您的数据库中是否有一个空的 Config 节点? 【参考方案1】:

您已接近解决方案,但 Neo4j-OGM(Spring Data Neo4j 中用于对象图映射的库)存在技术限制:当使用 @Properties 注释时,它只会保留并加载前缀(默认属性名称)具有正确分隔符的那些(默认.)。所以基本上在你的情况下,它只会加载以properties. 为前缀的属性,而不是所有返回的属性。

在 Spring Data Neo4j 中,还可以提供可被视为 DTO 的 @QueryResult。您可以使用注释标记中间类。请确保该类也是您的实体扫描的一部分。

@QueryResult
public class ConfigDto 

  private String name;

  private Map<String, String> properties;


如果您将 SDN 存储库方法的返回类型也更改为此类型

@Query("MATCH p = SHORTESTPATH((c2:Config)<-[:OVERRIDES*]-(c1:Config))"
 + " WHERE c1.name = 'Child' and not (c2)-[:OVERRIDES]->()"
 + " UNWIND NODES(p) as props return props.name as name, PROPERTIES(props) as properties")
List<ConfigDto> configs();

并且比使用这个方法,它会返回:

ConfigDtoname='Child', properties=a.exclusive=1, name=parentConfig, a.override=parent value
ConfigDtoname='Child', properties=a.exclusiveChild=my value, name=Child, a.override=child value

请注意,我编写了一个持久化“原始”Config 对象的测试,该对象具有如上所映射的属性,我只是在它们前面加上 a.。您可以看到该名称也在查询返回的属性映射中,因此该映射包含节点的所有属性。

编辑(保存来自 cmets 的部分) 使用上述解决方案,可以从 Neo4j 加载现有数据。

除了@Properties 解决方案之外,不可能保留任意属性,但这会在您的图形中创建“前缀”、“分隔”属性。例如。使用问题中的代码,您将获得properties.docker_tag

例如,您可以为Map 编写自己的属性转换器,并从https://github.com/neo4j/neo4j-ogm/blob/master/core/src/main/java/org/neo4j/ogm/typeconversion/MapCompositeConverter.java 获取一些想法 这是转换器的documentation 的链接,您应该实现CompositeAttributeConverter

Neo4j-OGM 并不意味着始终使用更改属性名称,如果域类本身中存在带有nameA 的属性并且也在这样的属性中定义,那么决定保存什么也会很复杂地图。

【讨论】:

谢谢!使用 DTO 可以按预期工作。我该如何坚持呢?使用ConfigConfigDto 我正在尝试编写插入测试。我扩展了Neo4jRepository&lt;Config, Long&gt;,但我没有看到插入方法。 :-( 忽略我的上一条评论 - 你能告诉我插入应该是什么样子吗?还是我应该开始另一个问题? 使用“属性”前缀,我发出这个查询,但我刚刚创建的节点没有返回。 MATCH (c1:Config) WHERE c1.properties.name = configName RETURN c1。而且该查询在 CQL Web 浏览器中根本不起作用。它不喜欢“。”字首。我很困惑....很想和你聊天!我在 -4 GMT。

以上是关于Neo4j:不知道如何将图形映射到 Spring Data bean的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data REST Neo4j 创建关系

如何将Spring Boot RepositoryRestResource映射到特定的URL

获取每个关系neo4j的路径长度

如何可视化从嵌入式 Neo4j Java 应用程序创建的 Neo4j 图形数据库

Neo4j - 图形数据科学库 - 如何对图形目录中的命名图形进行密码查询?

Neo4j - 将节点标题设置为 Web 界面中的标签