// Label-conditional degree statistics: the average number of relationships// of one type, in one direction, per node carrying one label. The global// AvgDegree averages a type's count over the type's OWN sources, which says// nothing about how a particular label's nodes fan out over it -- a type// whose rels overwhelmingly leave one label reads as a huge average for// every label that merely touches it. A chain-cost estimator multiplying// hop fan-outs needs the conditional form, or a low-cardinality anchor// hides an exploding chain behind it.
package chickpeas// labelDegreeEntry is one label's per-type incident-rel counts by// direction, summed over every node carrying the label. Zero-degree// members stay in the denominator: the statistic answers "expected fan-out// of a node with this label", not "average over nodes having such a rel".type labelDegreeEntry struct { out, in map[RelType]uint64}// labelDegreeStats returns (building once) the label's per-type degree// counts. Same lazy-cache choreography as the other snapshot indexes:// check under lock, build outside it, re-acquire and keep the first// insert.func ( *Snapshot) ( Label) *labelDegreeEntry { .labelDegreeMu.Lock()if , := .labelDegrees[]; { .labelDegreeMu.Unlock()return } .labelDegreeMu.Unlock() := &labelDegreeEntry{out: map[RelType]uint64{}, in: map[RelType]uint64{}}if , := .labelIndex[]; {for := range .Iter() { := int()if +1 < len(.outOffsets) {for := .outOffsets[]; < .outOffsets[+1]; ++ { .out[.outTypes[]]++ } }if +1 < len(.inOffsets) {for := .inOffsets[]; < .inOffsets[+1]; ++ { .in[.inTypes[]]++ } } } } .labelDegreeMu.Lock()defer .labelDegreeMu.Unlock()if , := .labelDegrees[]; {return } .labelDegrees[] = return}// AvgDegreeByLabel is AvgDegree conditioned on the node's label: the// average number of relType relationships in dir per node carrying label,// zero-degree members included. ok is false for an unknown or empty label// (the caller falls back to the global statistic); a known label with no// such rels answers (0, true) -- a real "this hop never fires" fact, not// a missing statistic. Both averages the two directions' counts together.func ( *Snapshot) (, string, Direction) (float64, bool) { , := .Label()if ! {return0, false } , := .labelIndex[]if ! || .Len() == 0 {return0, false } , := .RelType()if ! {return0, true } := .labelDegreeStats() := float64(.Len())switch {caseOutgoing:returnfloat64(.out[]) / , truecaseIncoming:returnfloat64(.in[]) / , true }returnfloat64(.out[]+.in[]) / , true}
The pages are generated with Goldsv0.8.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.