【问题标题】:SDN4 or neo4j-ogm performances issueSDN4 或 neo4j-ogm 性能问题
【发布时间】:2015-10-01 10:14:17
【问题描述】:

我编写了一些简单的 java 代码,但在 SDN4 中遇到了一些我在 SDN3 中没有的糟糕性能。我怀疑 find repositories methods depth 参数不能完全按照它应该的方式工作。让我解释一下问题:

这是我的 java 类(这只是一个示例),其中我删除了 getter、setter、contructors……

第一类是“元素”:

@NodeEntity
public class Element {

@GraphId
private Long id;

private int age;

private String  uuid;

@Relationship(type = "HAS_VALUE", direction = Relationship.OUTGOING)
private Set<Value> values = new HashSet<Value>();

第二个是'属性'

@NodeEntity
public class Attribute {
@GraphId
private Long id;

@Relationship(type = "HAS_PROPERTIES", direction = Relationship.OUTGOING)
private Set<HasInterProperties> properties;

“值”类允许我的用户在元素上为特定属性添加值:

@RelationshipEntity(type = "HAS_VALUE")
public class Value {

@GraphId
private Long id;

@StartNode
Element element;

@EndNode
Attribute attribute;

private Integer value;

private String uuid;

public Value() {
}

public Value(Element element, Attribute attribute, Integer value) {
    this.element = element;
    this.attribute = attribute;
    this.value = value;
    this.element.getValues().add(this);
    this.uuid = UUID.randomUUID().toString();
}

'Element' 类确实需要知道它的值,但 'Attribute' 类根本不关心值。

一个属性在 InternationalizedProperties 类上有引用,就像这样:

@NodeEntity
public class InternationalizedProperties {
@GraphId
private Long id;

private String name;

一个属性和它的InternationalizedProperties之间的关系实体如下:

@RelationshipEntity(type = "HAS_PROPERTIES")
public class HasInterProperties {

@GraphId
private Long id;

@StartNode
private Attribute attribute;

@EndNode
private InternationalizedProperties properties;

private String locale;

然后我创建了一个小的 main 方法来创建两个属性和 10000 个元素。我所有的元素对第一个属性都有一个特定的值,但对第二个没有值(它们之间没有关系)。这两个属性都有两个不同的国际化属性。这是一个示例:

public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("spring/*.xml");
     Session session = context.getBean(Session.class);
    session.query("START n=node(*) OPTIONAL MATCH n-[r]-() WHERE ID(n) <> 0 DELETE n,r", new HashMap<String, Object>());
    ElementRepository elementRepository = context.getBean(ElementRepository.class);
    AttributeRepository attributeRepository = context.getBean(AttributeRepository.class);
    InternationalizedPropertiesRepository internationalizedPropertiesRepository = context.getBean(InternationalizedPropertiesRepository.class);
    HasInterPropertiesRepository hasInterPropertiesRepository = context.getBean(HasInterPropertiesRepository.class);

    //Creation of an attribute object with two internationalized properties
    Attribute att = new Attribute();
    attributeRepository.save(att);
    InternationalizedProperties p1 = new InternationalizedProperties();
    p1.setName("bonjour");
    internationalizedPropertiesRepository.save(p1);
    InternationalizedProperties p2 = new InternationalizedProperties();
    p2.setName("hello");
    internationalizedPropertiesRepository.save(p2);
    hasInterPropertiesRepository.save(new HasInterProperties(att, p1, "fr"));
    hasInterPropertiesRepository.save(new HasInterProperties(att, p2, "en"));
    LOGGER.info("First attribut id is {}", att.getId());

    //Creation of 1000 elements having a differnt value on a same attribute

    for(int i = 0; i< 10000; i++) {
        Element elt = new Element();
        new Value(elt, att, i);
        elementRepository.save(elt);
        if(i%50 == 0) {
            LOGGER.info("{} elements created. Last element created with id {}", i+1, elt.getId());
        }
    }

    //Another attribut without any values from element.
    Attribute att2 = new Attribute();
    attributeRepository.save(att2);
    InternationalizedProperties p12 = new InternationalizedProperties();
    p12.setName("bonjour");
    internationalizedPropertiesRepository.save(p12);
    InternationalizedProperties p22 = new InternationalizedProperties();
    p22.setName("hello");
    internationalizedPropertiesRepository.save(p22);
    hasInterPropertiesRepository.save(new HasInterProperties(att2, p12, "fr"));
    hasInterPropertiesRepository.save(new HasInterProperties(att2, p22, "en"));
    LOGGER.info("Second attribut id is {}", att2.getId());

最后,在另一个主要方法中,我尝试多次获取第一个属性和第二个属性:

private static void getFirstAttribute(AttributeRepository attributeRepository) {
    StopWatch st = new StopWatch();
    st.start();
    Attribute attribute = attributeRepository.findOne(25283L, 1);
    LOGGER.info("time to get attribute (some element have values on it) is {}ms", st.getTime());
}

private static void getSecondAttribute(AttributeRepository attributeRepository) {
    StopWatch st = new StopWatch();
    st.start();
    Attribute attribute2 = attributeRepository.findOne(26286L, 1);
    LOGGER.info("time to get attribute (no element have values on it) is {}ms", st.getTime());
}

public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("spring/*.xml");

    AttributeRepository attributeRepository = context.getBean(AttributeRepository.class);

    getFirstAttribute(attributeRepository);
    getSecondAttribute(attributeRepository);

    getFirstAttribute(attributeRepository);
    getSecondAttribute(attributeRepository);

    getFirstAttribute(attributeRepository);
    getSecondAttribute(attributeRepository);

    getFirstAttribute(attributeRepository);
    getSecondAttribute(attributeRepository);
}

这里是这次执行的日志:

time to get attribute (some element have values on it) is 2983ms
time to get attribute (no element have values on it) is 4ms     
time to get attribute (some element have values on it) is 1196ms
time to get attribute (no element have values on it) is 2ms     
time to get attribute (some element have values on it) is 1192ms
time to get attribute (no element have values on it) is 3ms     
time to get attribute (some element have values on it) is 1194ms
time to get attribute (no element have values on it) is 3ms     

获取第二个属性(以及由于 depth=1 的国际化属性)非常快,但获取第一个属性仍然非常缓慢。我知道有很多关系(确切地说是 10000 个)指向第一个属性,但是当我想获得一个具有国际化属性的属性时,我显然不想获得所有指向它的值。 (因为未在 Attribute 类上指定 Set)。

这就是为什么我认为这里存在性能问题。还是我做错了什么?

感谢您的帮助

【问题讨论】:

    标签: neo4j spring-data-neo4j-4 neo4j-ogm


    【解决方案1】:

    从图表加载数据时,我们目前不分析您的域模型是如何连接在一起的,因此我们可能会带回您不需要的相关节点。如果它们在您的域中不可映射,则它们将被丢弃,但如果它们很多,则可能会影响响应时间。

    这种方法有两个原因。

    • 创建任意深度的通用查询显然比动态分析任意深度的域模型并生成即时自定义查询要简单得多;它也更容易分析和证明通用查询的正确性。

    • 我们希望保留支持多态域的能力 未来的模型,我们不一定知道里面有什么 数据库从一天到下一天,但我们想调整我们的域 根据我们的发现模拟水合作用。

    在这种情况下,我建议编写自定义查询来加载 Attribute 对象,以确保不会带回所有不需要的关系。

    【讨论】:

    • 我理解您的观点,但对我而言,这是 SDN3 的回归,其中获取数据更容易(id 总是在深度 1 处加载,如果用户想加载,可以按 id 获取节点对应的数据)。问题在于,在图形数据库中,许多节点都连接在一起,而我的示例正是我在图形中随处可见的东西。所以是的,我可以在我的示例中编写自定义查询,但在这种情况下,我必须编写自定义查询以在我的所有应用程序中加载(并保存?)数据......我打开了一个问题:github.com/neo4j/neo4j-ogm/issues/55 似乎@jexp同意这一点
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多