;; Extension — boolean-filtered ranked search (filter then rank by relevance).
;; Corpus:
;;   1 "apple apple banana"   apple2 banana1
;;   2 "apple cherry"         apple1 cherry1
;;   3 "banana cherry"        banana1 cherry1
;;   4 "apple banana cherry"  apple1 banana1 cherry1

(define
  rankq-setup
  "idx = indexDoc 4 \"apple banana cherry\" (indexDoc 3 \"banana cherry\" (indexDoc 2 \"apple cherry\" (indexDoc 1 \"apple apple banana\" emptyIndex)))\n")

(define
  rankq-cases
  (list
    (list
      "queryTerms and"
      "queryTerms (parseQuery \"apple AND banana\")"
      (list "apple" "banana"))
    (list
      "queryTerms or not"
      "queryTerms (parseQuery \"a OR NOT b\")"
      (list "a" "b"))
    (list
      "queryTerms phrase"
      "queryTerms (parseQuery \"\\\"x y\\\" OR z\")"
      (list "x" "y" "z"))
    (list
      "and filter ranked by tf"
      "searchRankTfIdf \"apple AND banana\" idx"
      (list 1 4))
    (list
      "single term ranked tie"
      "searchRankTfIdf \"cherry\" idx"
      (list 2 3 4))
    (list
      "or filter ranked"
      "searchRankTfIdf \"apple OR banana\" idx"
      (list 1 4 2 3))
    (list
      "and-not narrows then ranks"
      "searchRankTfIdf \"apple AND NOT banana\" idx"
      (list 2))
    (list
      "phrase filter ranked"
      "searchRankTfIdf \"\\\"apple banana\\\"\" idx"
      (list 1 4))
    (list "no matches" "searchRankTfIdf \"zzz\" idx" (list))
    (list
      "bm25 boolean ranked subset"
      "sort (searchRankBm25 1.5 0.75 \"apple OR banana\" idx)"
      (list 1 2 3 4))
    (list
      "bm25 and filter"
      "searchRankBm25 1.5 0.75 \"apple AND NOT banana\" idx"
      (list 2))))

(define
  rankq-results
  (search-batch rankq-setup (map (fn (c) (nth c 1)) rankq-cases)))

(map-indexed
  (fn
    (i c)
    (hk-test (nth c 0) (nth rankq-results i) (nth c 2)))
  rankq-cases)

{:fail hk-test-fail :pass hk-test-pass :fails hk-test-fails}
