ui: Generalize relevance computation.

* guix/ui.scm (relevance, package-relevance): New procedures.
(%package-metrics): New variable.
* guix/scripts/package.scm (find-packages-by-description)[score]
[package-score]: Remove.  Use 'package-relevance' instead.
This commit is contained in:
Ludovic Courtès 2017-09-13 15:07:17 +02:00
parent dab666cd8d
commit c7ae219e39
No known key found for this signature in database
GPG Key ID: 090B11993D9AEBB5
2 changed files with 44 additions and 20 deletions

@ -246,27 +246,8 @@ specified in MANIFEST, a manifest object."
"Return two values: the list of packages whose name, synopsis, or "Return two values: the list of packages whose name, synopsis, or
description matches at least one of REGEXPS sorted by relevance, and the list description matches at least one of REGEXPS sorted by relevance, and the list
of relevance scores." of relevance scores."
(define (score str)
(let ((counts (filter-map (lambda (regexp)
(match (regexp-exec regexp str)
(#f #f)
(m (match:count m))))
regexps)))
;; Compute a score that's proportional to the number of regexps matched
;; and to the number of matches for each regexp.
(* (length counts) (reduce + 0 counts))))
(define (package-score package)
(+ (* 3 (score (package-name package)))
(* 2 (match (package-synopsis package)
((? string? str) (score (P_ str)))
(#f 0)))
(match (package-description package)
((? string? str) (score (P_ str)))
(#f 0))))
(let ((matches (fold-packages (lambda (package result) (let ((matches (fold-packages (lambda (package result)
(match (package-score package) (match (package-relevance package regexps)
((? zero?) ((? zero?)
result) result)
(score (score

@ -85,6 +85,8 @@
string->recutils string->recutils
package->recutils package->recutils
package-specification->name+version+output package-specification->name+version+output
relevance
package-relevance
string->generations string->generations
string->duration string->duration
matching-generations matching-generations
@ -1024,6 +1026,47 @@ WIDTH columns. EXTRA-FIELDS is a list of symbol/value pairs to emit."
extra-fields) extra-fields)
(newline port)) (newline port))
(define (relevance obj regexps metrics)
"Compute a \"relevance score\" for OBJ as a function of its number of
matches of REGEXPS and accordingly to METRICS. METRICS is list of
field/weight pairs, where FIELD is a procedure that returns a string
describing OBJ, and WEIGHT is a positive integer denoting the weight of this
field in the final score.
A score of zero means that OBJ does not match any of REGEXPS. The higher the
score, the more relevant OBJ is to REGEXPS."
(define (score str)
(let ((counts (filter-map (lambda (regexp)
(match (regexp-exec regexp str)
(#f #f)
(m (match:count m))))
regexps)))
;; Compute a score that's proportional to the number of regexps matched
;; and to the number of matches for each regexp.
(* (length counts) (reduce + 0 counts))))
(fold (lambda (metric relevance)
(match metric
((field . weight)
(match (field obj)
(#f relevance)
(str (+ relevance
(* (score str) weight)))))))
0
metrics))
(define %package-metrics
;; Metrics used to compute the "relevance score" of a package against a set
;; of regexps.
`((,package-name . 3)
(,package-synopsis-string . 2)
(,package-description-string . 1)))
(define (package-relevance package regexps)
"Return a score denoting the relevance of PACKAGE for REGEXPS. A score of
zero means that PACKAGE does not match any of REGEXPS."
(relevance package regexps %package-metrics))
(define (string->generations str) (define (string->generations str)
"Return the list of generations matching a pattern in STR. This function "Return the list of generations matching a pattern in STR. This function
accepts the following patterns: \"1\", \"1,2,3\", \"1..9\", \"1..\", \"..9\"." accepts the following patterns: \"1\", \"1,2,3\", \"1..9\", \"1..\", \"..9\"."