我正在使用Spring-Data和SpringBoot來填充我的Neo4j圖形數據庫。有沒有辦法通過Neo4j Cypher查詢追蹤端到端數據沿襲?
我已經定義了以下Neo4j的實體:
Source
實體 - >
@NodeEntity
public class Source implements Comparable<Source> {
@GraphId private Long id;
private String name;
private SourceType type;
private String dataStoreName;
private String dataStoreDesc;
private Source() {
// Empty constructor required as of Neo4j API 2.0.5
};
public Source(String name, SourceType type, String dataStoreName, String dataStoreDesc) {
this.name = name;
this.type = type;
this.dataStoreName = dataStoreName;
this.dataStoreDesc = dataStoreDesc;
}
@Relationship(type = "CONTAINS", direction = Relationship.UNDIRECTED)
public Set<Field> fields;
public void contains(Field field) {
if (fields == null) {
fields = new HashSet<Field>();
}
fields.add(field);
}
/* Getter and Setters */
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public SourceType getType() {
return type;
}
public void setType(SourceType type) {
this.type = type;
}
public String getDataStoreName() {
return dataStoreName;
}
public void setDataStoreName(String dataStoreName) {
this.dataStoreName = dataStoreName;
}
public String getDataStoreDesc() {
return dataStoreDesc;
}
public void setDataStoreDesc(String dataStoreDesc) {
this.dataStoreDesc = dataStoreDesc;
}
public Set<Field> getFields() {
return fields;
}
public void setFields(Set<Field> fields) {
this.fields = fields;
}
@Override
public int compareTo(Source other) {
String name = other.getName();
SourceType type = other.getType();
if(this.name.equalsIgnoreCase(name) && this.type.equals(type))
return 0;
return -1;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((type == null) ? 0 : type.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;
Source other = (Source) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (type != other.type)
return false;
return true;
}
}
Field
實體 - >
@NodeEntity
public class Field implements Comparable<Field> {
@GraphId private Long id;
private String name;
private FieldType fieldType;
private SourceType sourceType;
private String logicalName;
private String dataType;
private String dataSize;
private String description;
private Field() {
// Empty constructor required as of Neo4j API 2.0.5
};
public Field(String name, FieldType fieldType, SourceType sourceType, String logicalName, String dataType, String dataSize, String description) {
this.name = name;
this.fieldType = fieldType;
this.sourceType = sourceType;
this.logicalName = logicalName;
this.dataType = dataType;
this.dataSize = dataSize;
this.description = description;
}
@Relationship(type = "MAPS-TO", direction = Relationship.UNDIRECTED)
public Set<Field> fields;
public void mapsTo(Field field) {
if (fields == null) {
fields = new HashSet<Field>();
}
fields.add(field);
}
/* Getter and Setters */
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public FieldType getFieldType() {
return fieldType;
}
public void setFieldType(FieldType fieldType) {
this.fieldType = fieldType;
}
public SourceType getSourceType() {
return sourceType;
}
public void setSourceType(SourceType sourceType) {
this.sourceType = sourceType;
}
public String getLogicalName() {
return logicalName;
}
public void setLogicalName(String logicalName) {
this.logicalName = logicalName;
}
public String getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public String getDataSize() {
return dataSize;
}
public void setDataSize(String dataSize) {
this.dataSize = dataSize;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Set<Field> getFields() {
return fields;
}
public void setFields(Set<Field> fields) {
this.fields = fields;
}
@Override
public int compareTo(Field other) {
String name = other.getName();
FieldType fieldType = other.getFieldType();
SourceType sourceType = other.getSourceType();
if(this.name.equalsIgnoreCase(name) && this.fieldType.equals(fieldType) && this.sourceType.equals(sourceType))
return 0;
return -1;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((fieldType == null) ? 0 : fieldType.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((sourceType == null) ? 0 : sourceType.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;
Field other = (Field) obj;
if (fieldType != other.fieldType)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (sourceType != other.sourceType)
return false;
return true;
}
}
所以,一個Source
CONTAINS
多Field
秒。而一個Field
是MAPS-TO
一個或多個其他Field
s。
每個Source
是SourceType
。
我不同的SourceType
s是:生產者,入場,舞臺,中級,出境,消費者。
public enum SourceType {
PRODUCER, INBOUND, STAGING, INTERMEDIATE, OUTBOUND, CONSUMER;
}
每個Field
是FieldType
的。我的不同FieldType
是:FILE_FIELD,DB_COLUMN。
public enum FieldType {
FILE_FIELD, DB_COLUMN;
}
我的數據血統如下: 生產者 - >入站 - > STAGING - >中間體 - >出站 - >消費
我現在正在尋找一種先進的Cypher查詢如果我在CONSUMER Source
中提供Field
,我可以跟蹤其歷史返回,直到PRODUCER Source
。
同樣,我也找了查詢通過,如果我的生產者Source
提供Field
,我能夠追蹤它的後裔向前直到消費者Source
。
我試圖建立使用shortestPath
和neighbors
函數查詢,但它似乎並沒有拉我正在尋找的結果。
任何建議/指針將不勝感激。
在此先感謝!
UPDATE-1在我的數據沿襲
背景: 我的應用程序從外部應用程序(產生)獲取文件。 我知道外部應用程序的數據庫表/列填充了文件中的字段。 所以這裏,PRODUCER將是我的Source
節點;外部應用程序(填充文件)的每個table.column是Field
節點,PRODUCER Source
節點將與所有Field
節點(表示填充文件的外部應用程序數據庫表的table.column)有CONTAINS
關係。
來自外部應用程序的文件被稱爲INBOUND。它是一個逗號分隔的文件。 我知道文件中的字段名稱以及順序是什麼。 所以在這裏,INBOUND將是我的Source
節點;文件中的每個字段將是一個Field
節點,並且INBOUND Source
節點將與所有Field
節點(表示入站文件中的文件字段)具有CONTAINS
關係。 INBOUND Source
的每個Field
節點與PRODUCER Source
(一對一映射)的Field
節點將具有MAPS_TO
關係。
繼續類似的工作流程,我的下一個階段被稱爲STAGING,其中我將入站文件字段加載到我的數據庫表/列中。 所以在這裏,STAGING將是我的Source
節點,並且數據庫表的每一列(我加載文件字段時)都將表示一個Field
節點。 STAGING源節點將與所有Field
節點(表示我加載文件字段的db表的db table.column)具有CONTAINS關係。 同樣,STAGING Source
的每個Field
節點將與INBOUND Source
(一對一映射)的Field
節點具有MAPS_TO
關係。
類似我的下一個階段是INTERMEDIATE。在這個階段,我正在查詢我加載輸入文件字段的表,然後將輸出刷新到另一個文件中(根據我的業務用例,我可能會選擇查詢全部或只有一部分表列從輸入文件填充)。 我知道什麼字段以什麼順序進入我的INTERMEDIATE文件。 所以在這裏,INTERMEDIATE是我的Source
節點,每個進入INTERMEDIATE文件的字段代表我的Field
節點。也中間Source
將與表示中間文件中的字段的所有Field
節點具有CONTAINS
關係。 此外,這些Field
節點中的每一個都將與STAGING Source(一對一映射)的字段具有MAPS_TO
關係。
同樣,我已經OUTBOUND階段和最後消費階段。
...(我希望你現在能夠以可視化的血統)
我查詢的目標是,比如說,如果我給一個Field
名(代表生產者的TABLE.COLUMN)作爲輸入,那麼我應該能夠追蹤它的血統,直到消費者(即我的血統的最後階段)。
快速註釋:Neo4j標籤不能有連字符,所以您應該將'MAPS-TO'更改爲'MAPS_TO'。 –
「不能有」或「不應該有」?因爲我已經用上面的關係填充了我的db,並且我可以在Neo4j上直觀地看到它們。 – lbvirgo
好的,所以你可以在圖中插入帶連字符的標籤,但Cypher不支持這些標籤。如果你試圖運行查詢MATCH(n) - [:MAPS-TO] - >(m)RETURN n,m',你將得到:'Invalid input' - ':期望一個標識符字符,空格,' |',長度說明,屬性圖或']'(第1行,第17列(偏移量:16))'。 –