diff options
authorArun Isaac2022-07-13 18:17:52 +0530
committerArun Isaac2022-07-19 17:37:07 +0530
commite00d944a93c92d401fa85ddf21b60f852bdd41f9 (patch)
parentf7170b4f5502f5aeb30620a2df4fc5a3049e9a95 (diff)
search: Sort by date on strictly boolean queries.
* issues/sort-by-date.gmi: Close issue. * tissue/search.scm (term-ref, query-terms-every): New functions. (boolean-query?): New public function. (search-fold): Sort by date on strictly boolean queries. * tissue/web/server.scm (handler): Sort by date on strictly boolean queries.
3 files changed, 55 insertions, 7 deletions
diff --git a/issues/sort-by-date.gmi b/issues/sort-by-date.gmi
index caa9ae7..8df8cc7 100644
--- a/issues/sort-by-date.gmi
+++ b/issues/sort-by-date.gmi
@@ -3,3 +3,9 @@
* tags: enhancement
The search page with a blank query doubles as a listing of all issues and documents. So, it is nicer if that listing is ordered by creation date. With actual non-blank search queries, it is ok to sort by relevance as we already do.
+## Resolution
+This is now implemented both for the web UI and the CLI. It was a bit more involved than first met the eye. We had to sort by date not just for "blank queries", but for all queries that had only boolean search terms---for example, "tag:enhancement" and "tag:enhancement AND type:issue AND is:open". To do this, we first indexed boolean terms as such. Earlier, we were indexing them as free text. Then, we parsed search queries with some prefixes being marked out as boolean prefixes. Finally, we iterated through the terms in parsed queries and checked if they were all boolean terms. If they were, then we sorted results by date.
+* closed
diff --git a/tissue/search.scm b/tissue/search.scm
index 08dd7f2..bc60c19 100644
--- a/tissue/search.scm
+++ b/tissue/search.scm
@@ -28,6 +28,7 @@
((parse-query) 'xapian:parse-query)
(else symbol))))
#:export (parse-query
+ boolean-query?
@@ -68,6 +69,33 @@ mapping field names to prefixes."
(QueryParser-parse-query query-parser search-query)))
+(define term-ref TermIterator-get-term)
+(define (query-terms-every pred query)
+ "Test whether every term in QUERY satisfies PRED. If so, return the
+result of the last PRED call. If not, return #f. The calls to PRED are
+made successively on the first, second, third, etc. term, and stopped
+when PRED returns #f."
+ (let loop ((head (Query-get-terms-begin query))
+ (result #t))
+ (cond
+ ((TermIterator-equals head (Query-get-terms-end query))
+ result)
+ ((pred head)
+ => (lambda (result)
+ (TermIterator-next head)
+ (loop head result)))
+ (else #f))))
+(define (boolean-query? query)
+ "Return #t if QUERY contains only boolean terms. Else, return #f."
+ (query-terms-every (lambda (term)
+ (any (match-lambda
+ ((field . prefix)
+ (string-contains? (term-ref term) prefix)))
+ %boolean-prefixes))
+ query))
(define* (search-fold proc initial db search-query
#:key (offset 0) (maximum-items (database-document-count db)))
"Search xapian database DB using SEARCH-QUERY and fold over the
@@ -88,7 +116,13 @@ return."
(MSetIterator-mset-get item)
- (enquire-mset (enquire db (parse-query search-query))
+ (enquire-mset (let* ((query (parse-query search-query))
+ (enquire (enquire db query)))
+ ;; Sort by recency date (slot 0) when
+ ;; query is strictly boolean.
+ (when (boolean-query? query)
+ (Enquire-set-sort-by-value enquire 0 #t))
+ enquire)
#:maximum-items maximum-items)))
(define* (search-map proc db search-query
diff --git a/tissue/web/server.scm b/tissue/web/server.scm
index 21fbf4a..1868591 100644
--- a/tissue/web/server.scm
+++ b/tissue/web/server.scm
@@ -287,12 +287,20 @@ STATE-DIRECTORY."
(call-with-database (string-append state-directory "/" hostname "/xapian")
(lambda (db)
- (let ((mset (enquire-mset (enquire db (new-Query (Query-OP-FILTER)
- (parse-query search-query)
- (or (assq-ref filter-alist search-type)
- (Query-MatchAll))))
- #:offset 0
- #:maximum-items (database-document-count db))))
+ (let* ((query (new-Query (Query-OP-FILTER)
+ (parse-query search-query)
+ (or (assq-ref filter-alist search-type)
+ (Query-MatchAll))))
+ (mset (enquire-mset
+ (let ((enquire (enquire db query)))
+ ;; Sort by recency date (slot
+ ;; 0) when query is strictly
+ ;; boolean.
+ (when (boolean-query? query)
+ (Enquire-set-sort-by-value enquire 0 #t))
+ enquire)
+ #:offset 0
+ #:maximum-items (database-document-count db))))
(mset-fold (lambda (item result)