func getFrequencyRelations(db *neoism.Database, r *model.Relationship, t *testing.T) int { res := []struct { Frequency int `json:"frequency"` }{} cq := neoism.CypherQuery{ Statement: fmt.Sprintf( ` MATCH (subject:%[1]s)-[r:%[2]s]->(object:%[3]s) WHERE subject.id = {subjectId} AND object.id = {objectId} RETURN r.frequency as frequency `, util.UpperCaseFirst(r.Subject), strings.ToUpper(r.Relationship), util.UpperCaseFirst(r.Object), ), Parameters: neoism.Props{"subjectId": r.SubjectID, "objectId": r.ObjectID}, Result: &res, } if err := db.Cypher(&cq); err != nil { assert.Fail(t, "Unexpected error: "+err.Error()) return -1 } if len(res) > 0 { return res[0].Frequency } return -1 }
// GetOrCreateNode returns a Node, creates one if it does not exist. This method // overrides the neoism one as there is a bug func GetOrCreateNode(db *neoism.Database, label, key string, p neoism.Props) (n *neoism.Node, created bool, err error) { node, created, err := db.GetOrCreateNode(util.UpperCaseFirst(label), key, p) // due to a bug in neoism, label is not added // see: https://github.com/jmcvetta/neoism/issues/62 if created { node.AddLabel(util.UpperCaseFirst(label)) } return node, created, err }
// DeleteRelationship deletes a relationship func DeleteRelationship(db *neoism.Database, r *model.Relationship) error { cq := neoism.CypherQuery{ Statement: fmt.Sprintf( ` MATCH (a:%s)-[r:%s]->(b:%s) WHERE a.id = {subjectId} AND b.id = {objectId} DELETE r `, util.UpperCaseFirst(r.Subject), strings.ToUpper(r.Relationship), util.UpperCaseFirst(r.Object), ), Parameters: neoism.Props{ "subjectId": r.SubjectID, "objectId": r.ObjectID, }, } return db.Cypher(&cq) }
// CreateOrIncRelationship creates a relationship or increments a property if it // already exists func CreateOrIncRelationship(db *neoism.Database, r *model.Relationship) error { cq := neoism.CypherQuery{ Statement: fmt.Sprintf( ` MATCH (a:%s), (b:%s) WHERE a.id = {subjectId} AND b.id = {objectId} CREATE UNIQUE (a)-[r:%s]->(b) SET r.frequency = COALESCE(r.frequency, 0) + 1 `, util.UpperCaseFirst(r.Subject), util.UpperCaseFirst(r.Object), strings.ToUpper(r.Relationship), ), Parameters: neoism.Props{ "subjectId": r.SubjectID, "objectId": r.ObjectID, }, } return db.Cypher(&cq) }
// GetRecommendations returns a list of recommended IDs func GetRecommendations(rq *model.RecommendationRequest) (*model.Recommendation, error) { // connect to graph db := GetGraph() res := []struct { ID string `json:"object.id"` Weight float32 `json:"weight"` }{} cq := neoism.CypherQuery{ Statement: fmt.Sprintf( // Currently we are using only COUNT // Since we store the number of times the relational event happened // We could have used SUM(r), however that is not useful for the // current use cases (a customer may view a product many times and // skew the results) ` MATCH (subject:%[1]s)-[:%[2]s]->(%[3]s)<-[:%[2]s]-(%[1]s)-[r:%[2]s]->(object:%[3]s) WHERE subject.id = {subjectId} AND NOT((subject)-[:%[2]s]->(object)) RETURN object.id, COUNT(r) AS weight ORDER BY weight DESC LIMIT %[4]d `, util.UpperCaseFirst(rq.Subject), strings.ToUpper(rq.Relationship), util.UpperCaseFirst(rq.Object), rq.Limit, ), Parameters: neoism.Props{"subjectId": rq.SubjectID}, Result: &res, } if err := db.Cypher(&cq); err != nil { return nil, err } recommendation := model.NewRecommendation() for _, result := range res { recommendation.Add(result.ID, result.Weight) } return recommendation, nil }