93 lines
2.5 KiB
Go
93 lines
2.5 KiB
Go
package retrieval
|
|
|
|
import "sort"
|
|
|
|
type Lane string
|
|
|
|
const (
|
|
LaneSemantic Lane = "SEMANTIC"
|
|
LaneEntity Lane = "ENTITY"
|
|
LaneTemporal Lane = "TEMPORAL"
|
|
LaneGoal Lane = "GOAL"
|
|
LanePositiveExperience Lane = "POSITIVE_EXPERIENCE"
|
|
LaneNegativeExperience Lane = "NEGATIVE_EXPERIENCE"
|
|
LaneContradiction Lane = "CONTRADICTION"
|
|
LaneSkill Lane = "SKILL"
|
|
)
|
|
|
|
// RetrievalDocument is disposable read-side projection data. SourceRef and
|
|
// Owner preserve provenance; this type never becomes canonical meaning.
|
|
type RetrievalDocument struct {
|
|
ID string
|
|
SourceRef string
|
|
Owner string
|
|
PrincipalID string
|
|
ContextScopeRef string
|
|
VersionRef string
|
|
Lane Lane
|
|
Text string
|
|
Relevance int
|
|
Freshness int
|
|
Confidence int
|
|
Salience int
|
|
Cost int
|
|
}
|
|
|
|
type Query struct {
|
|
PrincipalID string
|
|
ContextScopeRef string
|
|
VersionRef string
|
|
Lanes []Lane
|
|
Limit int
|
|
}
|
|
|
|
func FilterAndRank(documents []RetrievalDocument, query Query) []RetrievalDocument {
|
|
filtered := make([]RetrievalDocument, 0, len(documents))
|
|
for _, doc := range documents {
|
|
if doc.PrincipalID != query.PrincipalID || (query.ContextScopeRef != "" && doc.ContextScopeRef != query.ContextScopeRef) || (query.VersionRef != "" && doc.VersionRef != query.VersionRef) || !containsLane(query.Lanes, doc.Lane) {
|
|
continue
|
|
}
|
|
filtered = append(filtered, doc)
|
|
}
|
|
sort.SliceStable(filtered, func(i, j int) bool {
|
|
left := filtered[i].Relevance + filtered[i].Freshness + filtered[i].Confidence + filtered[i].Salience - filtered[i].Cost
|
|
right := filtered[j].Relevance + filtered[j].Freshness + filtered[j].Confidence + filtered[j].Salience - filtered[j].Cost
|
|
if left != right {
|
|
return left > right
|
|
}
|
|
return filtered[i].ID < filtered[j].ID
|
|
})
|
|
if query.Limit > 0 && len(filtered) > query.Limit {
|
|
filtered = filtered[:query.Limit]
|
|
}
|
|
return filtered
|
|
}
|
|
|
|
func containsLane(lanes []Lane, lane Lane) bool {
|
|
if len(lanes) == 0 {
|
|
return true
|
|
}
|
|
for _, v := range lanes {
|
|
if v == lane {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
type ProjectionBuilder interface {
|
|
Build() ([]RetrievalDocument, error)
|
|
}
|
|
|
|
func Rebuild(builders ...ProjectionBuilder) ([]RetrievalDocument, error) {
|
|
var result []RetrievalDocument
|
|
for _, builder := range builders {
|
|
docs, err := builder.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
result = append(result, docs...)
|
|
}
|
|
return result, nil
|
|
}
|