我目前正致力于创建一个使用neo4j存储每个网页内容的网络抓取工具。除了存储内容外,neo4j还用于存储页面之间的链接,稍后将用于计算页面排名。
我正在使用spring-data-neo4j 4.1.12.RELEASE,当我尝试更新两个节点之间的关系时遇到了问题。这是所有相关的代码。
网页(节点)
@NodeEntity
public class WebPage {
@GraphId
private Long nodeId;
private String url;
@Relationship(type = "LINKED_TO", direction = Relationship.OUTGOING)
private Set<Link> outgoingLinks = new HashSet<>();
public WebPage() {}
public String getUrl() {
return url;
}
public WebPage setUrl(String url) {
this.url = url;
return this;
}
@Relationship(type = "LINKED_TO", direction = Relationship.OUTGOING)
public Set<Link> getOutgoingLinks() {
return outgoingLinks;
}
@Relationship(type = "LINKED_TO", direction = Relationship.OUTGOING)
public void setOutgoingLinks(Set<Link> outgoingLinks) {
this.outgoingLinks = outgoingLinks;
}
public void addOutgoingLink(WebPage linkedWebPage, String anchor) {
Link outgoingLink = new Link(this, linkedWebPage, anchor);
outgoingLinks.remove(outgoingLink);
outgoingLinks.add(outgoingLink);
}
}
链接(关系)
@RelationshipEntity(type = "LINKED_TO")
public class Link {
@GraphId
Long id;
@StartNode
private WebPage sourceWebPage;
@EndNode
private WebPage linkWebPage;
@Property
private String anchor;
public Link() {}
public Link(WebPage sourceWebPage, WebPage linkWebPage, String anchor) {
this.sourceWebPage = sourceWebPage;
this.linkWebPage = linkWebPage;
this.anchor = anchor;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((linkWebPage == null) ? 0 : linkWebPage.hashCode());
result = prime * result + ((sourceWebPage == null) ? 0 : sourceWebPage.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Link other = (Link) obj;
if (linkWebPage == null) {
if (other.linkWebPage != null)
return false;
} else if (!linkWebPage.equals(other.linkWebPage))
return false;
if (sourceWebPage == null) {
if (other.sourceWebPage != null)
return false;
} else if (!sourceWebPage.equals(other.sourceWebPage))
return false;
return true;
}
@Override
public String toString() {
return "Link [sourceWebPage=" + sourceWebPage + ", linkWebPage=" + linkWebPage
+ ", anchor=" + anchor + "]";
}
}
@Repository
public interface WebPageRepository extends GraphRepository<WebPage>{
WebPage findByUrl(@Param("url") String url);
}
@Test
public void test() {
WebPage sourceWebPage = webPageRepository.findByUrl("http://www.test.com/");
if (sourceWebPage == null) {
sourceWebPage = new WebPage().setUrl("http://www.test.com/");
}
WebPage linkedWebPage = webPageRepository.findByUrl("http://www.example.com/");
if (linkedWebPage == null) {
linkedWebPage = new WebPage().setUrl("http://www.example.com/");
}
String anchor = "test";
sourceWebPage.addOutgoingLink(linkedWebPage, anchor);
webPageRepository.save(sourceWebPage);
}
注意
在链接域上覆盖了equals和hashCode,因此它只使用源WebPage和链接WebPage来确定相等性。我这样做是因为我不想在两个WebPages之间创建多个链接。因此,如果WebPage具有到另一个WebPage的多个链接,则所有锚点都在一个链接下收集。
问题
在测试中,我创建/找到两个WebPages,然后创建/更新两者之间的链接。以下是我用来更新链接的相关代码(来自上方)。
public void addOutgoingLink(WebPage linkedWebPage, String anchor) {
Link outgoingLink = new Link(this, linkedWebPage, anchor);
outgoingLinks.remove(outgoingLink);
outgoingLinks.add(outgoingLink);
}
问题是关系将在第一次测试时创建,但在第二次测试时删除。此创建和删除周期将无限期地继续。
这是一个运行示例,从数据库中没有数据开始。
运行#1
运行#2
运行#3,与#1相同
运行#4,与#2相同
有更好的方式来更新关系吗?从我的阅读来看,似乎更喜欢通过NodeEntity更新关系,因为使用@Query语法会导致数据同步问题。
非常感谢任何有关此问题的帮助。
谢谢!
马特