728x90
반응형
Graph DB 핸들링
- MATCH 로 조회한 데이터는 전부 Map으로 매핑된 데이터들
- 따라서 쿼리한 데이터를 가져올 때 GET 메서드로 데이터를 가져와야 함
- 아래는 처음에 짰던 코드
- 코드가 길고 가독성도 별로라서 다른 방안 고민 중 - 아래에 수정 내용 추가
result, queryErr := dbCon.Query(GetWordAndRelatedWord, map[string]interface{}{"word": word})
if queryErr != nil {
log.Printf("[SEARCH] Query Word Error: %v", queryErr)
return []SearchWordResult{}, queryErr
}
var queryResult []SearchWordResult
for _, data := range result {
name, isName := data.Get("name")
if !isName {
log.Printf("[SEARCH] No Name Found. Ignore. Word: %s", word)
continue
}
description, isDescription := data.Get("description")
if !isDescription {
log.Printf("[SEARCH] No Description Found. Ignore. Word: %s", word)
continue
}
createdAt, isCreatedAt := data.Get("created_at")
if !isCreatedAt {
log.Printf("[SEARCH] No CreatedAt Found. Ignore. Word: %s", word)
continue
}
updatedAt, isUpdatedAt := data.Get("updated_at")
if !isUpdatedAt {
log.Printf("[SEARCH] No UpdatedAt Found. Ignore. Word: %s", word)
continue
}
category, isCategory := data.Get("category")
if !isCategory {
log.Printf("[SEARCH] No Category Found. Ignore. Word: %s", word)
continue
}
createdBy, isCreatedBy := data.Get("created_by")
if !isCreatedBy {
log.Printf("[SEARCH] No CreatedBy Found. Ignore. Word: %s", word)
continue
}
var node = SearchWordResult{
Name: name.(string),
Category: category.(string),
Description: description.(string),
CreatedBy: createdBy.(string),
CreatedAt: createdAt.(string),
UpdatedAt: updatedAt.(string),
}
queryResult = append(queryResult, node)
}
데이터 핸들링 수정
- 처음에는 위처럼 데이터를 핸들링 했지만, 읽는 노드 개수가 여러개가 됨에 따라 그 데이터 형태가 달라졌다.
- 따라서 쿼리 방식을 바꿔야 했고, 데이터 형태 파악부터 해야 했다.
- 데이터는 배열 안에 각각 노드 Label에 따라 노드들이 배열에 담겨있었다.
- 따라서 쿼리 결과를 iteration 하며, 각각 label과 함께 나온 데이터를 핸들링하게 끔 수정했다.
- 쿼리 결과를 GET해서 가져왔을 때, 그 타입이 any 였다.
- 때문에 이를 dbtype.Node로 캐스팅하고, Node의 Properties를 뽑아와 사용했다.
- dbType은 neo4j에서 제공하는 노드 타입
- properties는 map[string]any 타입
- 때문에 이를 dbtype.Node로 캐스팅하고, Node의 Properties를 뽑아와 사용했다.
- 따라서 쿼리 방식을 바꿔야 했고, 데이터 형태 파악부터 해야 했다.
responseMap := make(map[string]*SearchWordResult)
for _, data := range result {
wNode, isNode := data.Get("word")
if !isNode {
log.Printf("[SEARCH] No Node Found")
continue
}
targetNode := wNode.(dbtype.Node)
rNode, isRelated := data.Get("related")
if !isRelated {
log.Printf("[SEARCH] No Related Node Found")
continue
}
relatedNodeList := rNode.(dbtype.Node)
wordeNode := SearchWordItem{
Name: targetNode.GetProperties()["name"].(string),
Category: targetNode.GetProperties()["category"].(string),
Description: targetNode.GetProperties()["description"].(string),
CreatedBy: targetNode.GetProperties()["created_by"].(string),
CreatedAt: targetNode.GetProperties()["created_at"].(string),
UpdatedAt: targetNode.GetProperties()["updated_at"].(string),
}
relatedNode := SearchWordItem{
Name: relatedNodeList.GetProperties()["name"].(string),
Category: relatedNodeList.GetProperties()["category"].(string),
Description: relatedNodeList.GetProperties()["description"].(string),
CreatedBy: relatedNodeList.GetProperties()["created_by"].(string),
CreatedAt: relatedNodeList.GetProperties()["created_at"].(string),
UpdatedAt: relatedNodeList.GetProperties()["updated_at"].(string),
}
if _, exists := responseMap[wordeNode.Name]; !exists {
responseMap[wordeNode.Name] = &SearchWordResult{
Word: wordeNode,
Related: []SearchWordItem{},
}
}
responseMap[wordeNode.Name].Related = append(responseMap[wordeNode.Name].Related, relatedNode)
}
var responseList []SearchWordResult
for _, response := range responseMap {
responseList = append(responseList, *response)
}
노드 및 관계 읽기
- 아래 쿼리 방식은 관계를 통한 조회이다.
- relations가 RELATED 혹은 PARENT 인 노드 관계들을 조회하고
- 1..2 는 hop에 관한 내용이다
- 1 은 직접적으로 연관된 노드들
- 2는 중간에 노드가 하나 있는 노드들
- 조회에 성공한 노드들 정보를 리턴한다
- SQL과 동일하게 DISTINCT 해서 리턴
- word의 경우 name 프로퍼티에 대한 조건 쿼리랑 동일하기 때문에 하나 혹은 동일한 이름을 가진 노드들 리턴
- related의 경우, 특정 이름을 가진 노드와 1홉 혹은 2홉의 관계를 가진 모든 노드들
MATCH (w:Word {name: $word})-[:RELATED|PARENT*1..2]-(related:Word)
RETURN DISTINCT word, related
관계 property 설정
- 실제 짜서 사용중인 코드이다. 아래처럼 관계를 설정한다.
- 방향이 설정되지 않은 관계는 RELATED
- 부모/자식 노드들의 관계를 PARENT / CHILDREN이라는 관계로 정의함
// Create Relations
var CreateWordRelatinon = `
MATCH (w1:Word{name: $name1}), (w2:Word{name: $name2})
MERGE (w1)-[r:RELATED]-(w2)
SET r.weight = $weight
`
// Create Relations; w1 is Parent, w2 is Children
var CreateWordParent = `
MATCH (w1:Word{name: $name1}), (w2:Word{name: $name2})
MERGE (w1)-[r:PARENT]->(w2)
SET r.weight = $weight
`
// Create Relations; w2 is Parent, w1 is Children
var CreateWordChildren = `
MATCH (w1:Word{name: $name1}), (w2:Word{name: $name2})
MERGE (w1)-[r:CHILDREN]->(w2)
SET r.weight = $weight
`
728x90
반응형
'백엔드 Backend > Golang' 카테고리의 다른 글
[Neo4j] Golang 으로 쿼리 핸들링 (0) | 2024.12.06 |
---|---|
[Neo4j] Golang으로 Neo4j 연동 (0) | 2024.12.05 |
[GO] Ubuntu 서버에 설치 (1) | 2024.10.30 |
[GO] Goroutine이란? (0) | 2024.10.02 |