Spring-Data を SpringBoot と共に使用して、Neo4j グラフ データベースにデータを入力しています。
次の 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
の s。aField
はMAPS-TO
1 つ以上の他Field
の s です。
それぞれSource
がSourceType
.
私の異なるSourceType
のは、プロデューサー、インバウンド、ステージング、中間、アウトバウンド、コンシューマーです。
public enum SourceType {
PRODUCER, INBOUND, STAGING, INTERMEDIATE, OUTBOUND, CONSUMER;
}
それぞれField
がFieldType
.
私の異なるFieldType
ものは次のとおりです。FILE_FIELD、DB_COLUMN。
public enum FieldType {
FILE_FIELD, DB_COLUMN;
}
私のデータ系統は次のとおりです: PRODUCER --> INBOUND --> STAGING --> INTERMEDIATE --> OUTBOUND --> CONSUMER
私は現在Field
、 CONSUMERに a を指定すると、 PRODUCER までSource
その系統を追跡できる高度Source
な Cypher クエリを探しています。
Field
同様に、 PRODUCERSource
に a を指定すると、その系統をCONSUMER まで追跡できるクエリも探していますSource
。
shortestPath
関数と関数を使用してクエリを作成しようとしましたneighbors
が、探している結果が得られないようです。
任意の提案/ポインタをいただければ幸いです。
前もって感謝します !
更新-1
私のデータ系統の背景: 私のアプリケーションは外部アプリケーション (PRODUCE) からファイルを取得します。ファイル内のフィールドに入力された外部アプリケーションのデータベース テーブル/列を認識しています。ここでは、PRODUCER が私のSource
ノードになります。外部アプリケーション (ファイルに入力された) の各 table.column はField
ノードであり、PRODUCERSource
ノードはCONTAINS
すべてのノードと関係を持ちField
ます (ファイルに入力された外部アプリケーション データベース テーブルの table.column を表します)。
外部アプリケーションからのファイルは INBOUND と呼ばれます。コンマ区切りファイルです。ファイルに含まれるフィールド名とその順序を認識しています。ここでは、INBOUND がSource
ノードになります。ファイル内の各フィールドはField
ノードになり、INBOUNDSource
ノードはCONTAINS
すべてのノードと関係を持ちField
ます (受信ファイルのファイル フィールドを表します)。またField
、INBOUNDの各ノードは、PRODUCERのノードと関係がありSource
ます(1 対 1 のマッピング)。MAPS_TO
Field
Source
同様のワークフローで、次の段階は STAGING と呼ばれ、受信ファイル フィールドをデータベース テーブル/列にロードします。ここでは、STAGING がSource
ノードになり、(ファイル フィールドをロードする) データベース テーブルの各列がField
ノードを表します。Field
STAGING ソース ノードは、すべてのノード (ファイル フィールドをロードする db テーブルの db table.column を表す)と CONTAINS 関係を持ちます。またField
、STAGINGの各ノードは、INBOUNDのノードと関係がありSource
ます(1 対 1 のマッピング)。MAPS_TO
Field
Source
同様に、私の次のステージは中級です。この段階では、入力ファイルのフィールドをロードしたテーブルに対してクエリを実行し、出力を別のファイルにフラッシュします (ビジネス ユース ケースに基づいて、テーブル列のすべてまたはサブセットのみをクエリすることを選択できます)。入力ファイルから取り込まれます)。どのフィールドがどの順序で INTERMEDIATE ファイルに入るかを知っています。ここで、INTERMEDIATE は私のSource
ノードであり、INTERMEDIATE ファイルに入る各フィールドは私のノードを表しField
ます。また、INTERMEDIATESource
は、中間ファイル内のフィールドを表すCONTAINS
すべてのノードと関係があります。Field
また、これらの各Field
ノードはMAPS_TO
、STAGING ソースのフィールドと関係があります (1 対 1 のマッピング)。
同様に、OUTBOUND ステージ、最後に CONSUMER ステージがあります。
…(血統を視覚化できるようになったと思います)
私のクエリの目的は、たとえば、Field
名前 (PRODUCER の table.column を表す) を入力として指定した場合、その系統を CONSUMER (つまり、私の系統の最後の段階) まで追跡できるようにすることです。