Пример #1
0
// handleMerge merges a list of vertices onto the final vertex in the Vertices list
func (d *Data) handleMerge(ctx *datastore.VersionedCtx, db storage.GraphDB, w http.ResponseWriter, labelgraph *LabelGraph) error {

	numverts := len(labelgraph.Vertices)
	if numverts < 2 {
		return fmt.Errorf("Must specify at least two vertices for merging")
	}

	overlapweights := make(map[dvid.VertexID]float64)
	vertweight := float64(0)
	var keepvertex dvid.GraphVertex
	allverts := make(map[dvid.VertexID]struct{})
	keepverts := make(map[dvid.VertexID]struct{})

	// accumulate weights, find common edges
	for i, vertex := range labelgraph.Vertices {
		vert, err := db.GetVertex(ctx, vertex.Id)
		if err != nil {
			return fmt.Errorf("Failed to retrieve vertex %d: %v\n", vertex.Id, err)
		}
		allverts[vert.Id] = struct{}{}
		vertweight += vert.Weight

		if i == (numverts - 1) {
			keepvertex = vert
		} else {
			for _, vert2 := range vert.Vertices {
				edge, err := db.GetEdge(ctx, vert.Id, vert2)
				if err != nil {
					return fmt.Errorf("Failed to retrieve edge %d-%d: %v\n", vertex.Id, vert2, err)
				}
				overlapweights[vert2] += edge.Weight
			}
		}
	}

	// examine keep vertex (save edges so only the weights are updated)
	for _, vert2 := range keepvertex.Vertices {
		edge, err := db.GetEdge(ctx, keepvertex.Id, vert2)
		if err != nil {
			return fmt.Errorf("Failed to retrieve edge %d-%d: %v\n", keepvertex.Id, vert2, err)
		}
		overlapweights[vert2] += edge.Weight
		keepverts[vert2] = struct{}{}
	}

	// use specified weights even if marked as 0
	for _, edge := range labelgraph.Edges {
		id := edge.Id1
		baseid := edge.Id2
		if keepvertex.Id == edge.Id1 {
			id = edge.Id2
			baseid = edge.Id1
		}
		if baseid == keepvertex.Id {
			if _, ok := overlapweights[id]; ok {
				overlapweights[id] = edge.Weight
			}
		}
	}

	// if user specifies an edge weight other than 0 (?! -- somehow allow in future)
	// use that weight
	if labelgraph.Vertices[numverts-1].Weight != 0 {
		vertweight = labelgraph.Vertices[numverts-1].Weight
	}

	for id2, newweight := range overlapweights {
		if _, ok := allverts[id2]; !ok {
			// only examine edges where the node is not internal
			if _, ok := keepverts[id2]; !ok {
				// if not in keepverts create new edge
				err := db.AddEdge(ctx, keepvertex.Id, id2, newweight)
				if err != nil {
					return fmt.Errorf("Failed to create edge %d-%d: %v\n", keepvertex.Id, id2, err)
				}
			} else {
				// else just update weight
				err := db.SetEdgeWeight(ctx, keepvertex.Id, id2, newweight)
				if err != nil {
					return fmt.Errorf("Failed to update weight on edge %d-%d: %v\n", keepvertex.Id, id2, err)
				}
			}
		}
	}

	// update vertex weight
	err := db.SetVertexWeight(ctx, labelgraph.Vertices[numverts-1].Id, vertweight)
	if err != nil {
		return fmt.Errorf("Failed to update weight on vertex %d: %v\n", keepvertex.Id, err)
	}

	// remove old vertices which will remove the old edges
	for i, vertex := range labelgraph.Vertices {
		if i == (numverts - 1) {
			break
		}
		err := db.RemoveVertex(ctx, vertex.Id)
		if err != nil {
			return fmt.Errorf("Failed to remove vertex %d: %v\n", vertex.Id, err)
		}
	}
	return nil
}
Пример #2
0
// handleWeightUpdate POST vertex/edge weight increment/decrement.  POSTing to an uncreated
// node or edge will create the node or edge (default 0 weight).  Limit of 1000 vertices and 1000 edges.
func (d *Data) handleWeightUpdate(ctx *datastore.VersionedCtx, db storage.GraphDB, w http.ResponseWriter, labelgraph *LabelGraph) error {

	// collect all vertices that need to be locked and wrap in transaction ("read only")
	open_vertices := d.extractOpenVertices(labelgraph)
	transaction_group, err := d.transaction_log.createTransactionGroup(open_vertices, true)

	if err != nil {
		transaction_group.closeTransaction()
		return fmt.Errorf("Could not create transaction group")
	}

	leftover := true

	// iterate until leftovers are empty
	for leftover {
		if len(transaction_group.lockedold_ids) == 0 {
			leftover = false
		}

		for i, vertex := range labelgraph.Vertices {
			// if it was already examined, continue
			if vertex.Id == 0 {
				continue
			}
			// if it the vertex was not locked, continue
			if _, ok := transaction_group.locked_ids[vertex.Id]; !ok {
				continue
			}

			// retrieve vertex, update or create depending on error status
			storedvert, err := db.GetVertex(ctx, vertex.Id)
			if err != nil {
				err = db.AddVertex(ctx, vertex.Id, vertex.Weight)
				if err != nil {
					transaction_group.closeTransaction()
					return fmt.Errorf("Failed to add vertex: %v\n", err)
				}
			} else {
				// increment/decrement weight
				err = db.SetVertexWeight(ctx, vertex.Id, storedvert.Weight+vertex.Weight)
				if err != nil {
					transaction_group.closeTransaction()
					return fmt.Errorf("Failed to add vertex: %v\n", err)
				}
			}

			// do not revisit
			labelgraph.Vertices[i].Id = 0
		}
		for i, edge := range labelgraph.Edges {
			// if it was already examined, continue
			if edge.Id1 == 0 {
				continue
			}

			// if it the edge was not locked, continue
			if _, ok := transaction_group.locked_ids[edge.Id1]; !ok {
				continue
			}
			if _, ok := transaction_group.locked_ids[edge.Id2]; !ok {
				continue
			}

			// retrieve edge, update or create depending on error status
			storededge, err := db.GetEdge(ctx, edge.Id1, edge.Id2)
			if err != nil {
				err = db.AddEdge(ctx, edge.Id1, edge.Id2, edge.Weight)
				if err != nil {
					transaction_group.closeTransaction()
					return fmt.Errorf("Failed to add edge: %v\n", err)
				}
			} else {
				// increment/decrement weight
				err = db.SetEdgeWeight(ctx, edge.Id1, edge.Id2, storededge.Weight+edge.Weight)
				if err != nil {
					transaction_group.closeTransaction()
					return fmt.Errorf("Failed to update edge: %v\n", err)
				}
			}

			// do not revisit
			labelgraph.Edges[i].Id1 = 0
		}

		if leftover {
			// wait on update to channel if there are leftovers
			transaction_group.waitForChange()

			// close transaction, create new transaction from leftovers in labelgraph
			transaction_group.closeTransaction()
			open_vertices = d.extractOpenVertices(labelgraph)
			transaction_group, _ = d.transaction_log.createTransactionGroup(open_vertices, true)
		}
	}

	transaction_group.closeTransaction()
	return nil
}