Ejemplo n.º 1
0
func (g *graphObject) Vertex(call otto.FunctionCall) otto.Value {
	qv, err := toQuadValues(exportArgs(call.ArgumentList))
	if err != nil {
		//TODO(dennwc): pass error to caller
		return otto.NullValue()
	}
	return outObj(call, &pathObject{
		wk:     g.wk,
		finals: true,
		path:   path.StartMorphism(qv...),
	})
}
Ejemplo n.º 2
0
func buildPathFromObject(obj *otto.Object) *path.Path {
	var p *path.Path
	val, _ := obj.Get("_gremlin_type")
	stringArgs := propertiesOf(obj, "string_args")
	gremlinType := val.String()
	if prev, _ := obj.Get("_gremlin_prev"); !prev.IsObject() {
		switch gremlinType {
		case "vertex":
			return path.StartMorphism(stringArgs...)
		case "morphism":
			return path.StartMorphism()
		default:
			panic("No base gremlin path other than 'vertex' or 'morphism'")
		}
	} else {
		p = buildPathFromObject(prev.Object())
	}
	if p == nil {
		return nil
	}
	switch gremlinType {
	case "Is":
		return p.Is(stringArgs...)
	case "In":
		preds, tags, ok := getViaData(obj)
		if !ok {
			return nil
		}
		return p.InWithTags(tags, preds...)
	case "Out":
		preds, tags, ok := getViaData(obj)
		if !ok {
			return nil
		}
		return p.OutWithTags(tags, preds...)
	case "Both":
		preds, _, ok := getViaData(obj)
		if !ok {
			return nil
		}
		return p.Both(preds...)
	case "Follow":
		subobj := getFirstArgAsMorphismChain(obj)
		if subobj == nil {
			return nil
		}
		return p.Follow(buildPathFromObject(subobj))
	case "FollowR":
		subobj := getFirstArgAsMorphismChain(obj)
		if subobj == nil {
			return nil
		}
		return p.FollowReverse(buildPathFromObject(subobj))
	case "And", "Intersect":
		subobj := getFirstArgAsVertexChain(obj)
		if subobj == nil {
			return nil
		}
		return p.And(buildPathFromObject(subobj))
	case "Union", "Or":
		subobj := getFirstArgAsVertexChain(obj)
		if subobj == nil {
			return nil
		}
		return p.Or(buildPathFromObject(subobj))
	case "Back":
		if len(stringArgs) != 1 {
			return nil
		}
		return p.Back(stringArgs[0])
	case "Tag", "As":
		return p.Tag(stringArgs...)
	case "Has":
		if len(stringArgs) < 2 {
			return nil
		}
		return p.Has(stringArgs[0], stringArgs[1:]...)
	case "Save", "SaveR":
		if len(stringArgs) > 2 || len(stringArgs) == 0 {
			return nil
		}
		tag := stringArgs[0]
		if len(stringArgs) == 2 {
			tag = stringArgs[1]
		}
		if gremlinType == "SaveR" {
			return p.SaveReverse(stringArgs[0], tag)
		}
		return p.Save(stringArgs[0], tag)
	case "Except", "Difference":
		subobj := getFirstArgAsVertexChain(obj)
		if subobj == nil {
			return nil
		}
		return p.Except(buildPathFromObject(subobj))
	case "InPredicates":
		return p.InPredicates()
	case "OutPredicates":
		return p.OutPredicates()
	case "LabelContext":
		labels, tags, ok := getViaData(obj)
		if !ok {
			return nil
		}
		return p.LabelContextWithTags(tags, labels...)
	default:
		panic(fmt.Sprint("Unimplemented Gremlin function", gremlinType))
	}
}
Ejemplo n.º 3
0
func recommendationStory(sr *server, keys []string, limit, offset int) (recResp, error) {
	start := time.Now()
	g := sr.graph
	s := storyByKey(g, keys[0])
	log.Printf("Finding recommendations for \"%s\"...", s.Title)
	recStories := make(map[string]float64)

	// Fetch users first.
	paths := []struct {
		desc string
		path *path.Path
	}{
		{
			StoryFavoritedBy,
			path.StartMorphism(keys...).Out(StoryFavoritedBy),
		},
		{
			StoryAuthor,
			path.StartMorphism(keys...).Out(StoryAuthor),
		},
	}
	var users []string
	for _, path := range paths {
		startOpt := time.Now()
		it, _ := path.path.BuildIteratorOn(g).Optimize()
		defer it.Close()
		log.Printf("%s: BuildIterator().Optimize() took %s", path.desc, time.Now().Sub(startOpt))

		startFetch := time.Now()
		nexter := it.(graph.Nexter)
		for nexter.Next() {
			users = append(users, g.NameOf(it.Result()))
		}
		log.Printf("%s: cayley.RawNext(it) took %s", path.desc, time.Now().Sub(startFetch))
	}

	// Fetch users' stories and favorites.
	paths2 := []struct {
		desc string
		path *path.Path
	}{
		{
			UserFavoriteStory,
			path.StartMorphism(users...).Out(UserFavoriteStory),
		},
		{
			UserStory,
			path.StartMorphism(users...).Out(UserStory),
		},
	}
	for _, path := range paths2 {
		startOpt := time.Now()
		it, _ := path.path.BuildIteratorOn(g).Optimize()
		defer it.Close()
		log.Printf("%s: BuildIterator().Optimize() took %s", path.desc, time.Now().Sub(startOpt))

		startFetch := time.Now()
		nexter := it.(graph.Nexter)
		for nexter.Next() {
			stID := g.NameOf(it.Result())
			recStories[stID]++
		}
		log.Printf("%s: cayley.RawNext(it) took %s", path.desc, time.Now().Sub(startFetch))
	}

	// Remove favorites pointing to original story.
	for _, key := range keys {
		delete(recStories, key)
	}

	favorites := 0
	for _, count := range recStories {
		favorites += int(count)
	}

	stories := make([]string, 0, len(recStories))
	for st := range recStories {
		stories = append(stories, st)
	}

	/*
		// Weight stories by sum of shared favorites * log(# favorites) / # favorites
		it2, _ := cayley.StartPath(g, stories...).Save(StoryFavorites, StoryFavorites).BuildIterator().Optimize()
		defer it2.Close()
		for i := 0; cayley.RawNext(it2); i++ {
			story := stories[i]
			results := map[string]graph.Value{}
			it2.TagResults(results)
			favorites := float64(atoi(g.NameOf(results[StoryFavorites])))
			if favorites == 0 {
				continue
			}
			val := recStories[story]
			recStories[story] = val * math.Log(val) / favorites
		}
	*/

	rsl := sortMap(recStories)
	if len(rsl) != len(stories) {
		log.Fatalf("len(rsl) = %d, len(stories) = %d", len(rsl), len(stories))
	}
	storyCount := len(rsl)
	if len(rsl) > (limit + offset) {
		rsl = rsl[offset : offset+limit]
	} else if len(rsl) > offset {
		rsl = rsl[offset:]
	} else {
		rsl = nil
	}
	startStories := time.Now()
	sOut := storiesByKeys(g, rsl)
	log.Printf("storiesByKeys(len = %d) took %s", len(rsl), time.Now().Sub(startStories))
	for i, st := range sOut {
		st.annotate()
		st.Score = float32(recStories[rsl[i]])
	}
	s.annotate()
	resp := recResp{
		sOut,
		nil,
		&s,
		respStats{
			storyCount,
			favorites,
			len(users),
		},
	}

	log.Printf("recommendationStory(%q) took %s, stats %+v", s.Title, time.Now().Sub(start), resp.Stats)
	return resp, nil
}
Ejemplo n.º 4
0
func (g *graphObject) Morphism(call otto.FunctionCall) otto.Value {
	return outObj(call, &pathObject{
		wk:   g.wk,
		path: path.StartMorphism(),
	})
}