Pure ranking and scoring functions for search results.
This namespace provides functions for calculating relevance scores, applying boosts, and normalizing results. All functions are pure.
Architecture: Functional Core (Pure)
Pure ranking and scoring functions for search results. This namespace provides functions for calculating relevance scores, applying boosts, and normalizing results. All functions are pure. Architecture: Functional Core (Pure)
(add-rank-position results)Add rank position (1, 2, 3...) to results.
Args: results - Sorted list of results
Returns: Results with :rank field added (as vector)
Example: (add-rank-position [{:score 0.9} {:score 0.7}]) ;=> [{:score 0.9 :rank 1} {:score 0.7 :rank 2}]
Pure: true
Add rank position (1, 2, 3...) to results.
Args:
results - Sorted list of results
Returns:
Results with :rank field added (as vector)
Example:
(add-rank-position [{:score 0.9} {:score 0.7}])
;=> [{:score 0.9 :rank 1} {:score 0.7 :rank 2}]
Pure: true(apply-linear-recency-boost base-score document-age-days)(apply-linear-recency-boost base-score document-age-days max-boost decay-days)Apply linear decay boost for recent documents.
Simpler than exponential decay. Boost decreases linearly with age.
Args: base-score - Original relevance score document-age-days - Age in days max-boost - Maximum boost for brand new documents (default: 2.0 = 2x) decay-days - Days until boost reaches 0 (default: 30)
Returns: Boosted score
Example: ;; Brand new document gets 2x boost (apply-linear-recency-boost 0.5 0 2.0 30) ;=> 1.0
;; 15 day old document gets 1.5x boost (apply-linear-recency-boost 0.5 15 2.0 30) ;=> 0.75
;; 30+ day old document gets no boost (apply-linear-recency-boost 0.5 35 2.0 30) ;=> 0.5
Pure: true
Apply linear decay boost for recent documents. Simpler than exponential decay. Boost decreases linearly with age. Args: base-score - Original relevance score document-age-days - Age in days max-boost - Maximum boost for brand new documents (default: 2.0 = 2x) decay-days - Days until boost reaches 0 (default: 30) Returns: Boosted score Example: ;; Brand new document gets 2x boost (apply-linear-recency-boost 0.5 0 2.0 30) ;=> 1.0 ;; 15 day old document gets 1.5x boost (apply-linear-recency-boost 0.5 15 2.0 30) ;=> 0.75 ;; 30+ day old document gets no boost (apply-linear-recency-boost 0.5 35 2.0 30) ;=> 0.5 Pure: true
(apply-recency-boost base-score document-age-days)(apply-recency-boost base-score document-age-days decay-factor)Apply exponential decay boost for recent documents.
Boosts recent documents' scores to prefer fresh content. Uses exponential decay: score * (1 + e^(-decay * age))
Args: base-score - Original relevance score (0-1) document-age-days - Age of document in days decay-factor - Decay rate (default: 0.1) Higher = faster decay (prefer very recent docs) Lower = slower decay (prefer recent but not too aggressive)
Returns: Boosted score
Example: ;; Recent document (1 day old) gets significant boost (apply-recency-boost 0.5 1 0.1) ;=> ~0.95
;; Older document (30 days) gets small boost (apply-recency-boost 0.5 30 0.1) ;=> ~0.52
;; Very old document (100 days) gets no boost (apply-recency-boost 0.5 100 0.1) ;=> ~0.50
Pure: true
Apply exponential decay boost for recent documents.
Boosts recent documents' scores to prefer fresh content.
Uses exponential decay: score * (1 + e^(-decay * age))
Args:
base-score - Original relevance score (0-1)
document-age-days - Age of document in days
decay-factor - Decay rate (default: 0.1)
Higher = faster decay (prefer very recent docs)
Lower = slower decay (prefer recent but not too aggressive)
Returns:
Boosted score
Example:
;; Recent document (1 day old) gets significant boost
(apply-recency-boost 0.5 1 0.1)
;=> ~0.95
;; Older document (30 days) gets small boost
(apply-recency-boost 0.5 30 0.1)
;=> ~0.52
;; Very old document (100 days) gets no boost
(apply-recency-boost 0.5 100 0.1)
;=> ~0.50
Pure: true(calculate-average-score results)Calculate average score across results.
Args: results - List of result maps with :score
Returns: Average score (float)
Example: (calculate-average-score [{:score 0.8} {:score 0.6} {:score 0.4}]) ;=> 0.6
Pure: true
Calculate average score across results.
Args:
results - List of result maps with :score
Returns:
Average score (float)
Example:
(calculate-average-score [{:score 0.8} {:score 0.6} {:score 0.4}])
;=> 0.6
Pure: true(calculate-document-age-days created-at current-time)Calculate document age in days.
Args: created-at - java.time.Instant, java.sql.Timestamp, or string timestamp current-time - java.time.Instant
Returns: Age in days (integer)
Example: (calculate-document-age-days #inst "2024-01-01" #inst "2024-01-08") ;=> 7
Pure: true
Calculate document age in days. Args: created-at - java.time.Instant, java.sql.Timestamp, or string timestamp current-time - java.time.Instant Returns: Age in days (integer) Example: (calculate-document-age-days #inst "2024-01-01" #inst "2024-01-08") ;=> 7 Pure: true
(calculate-field-weight field config)Calculate weight for field based on configuration.
PostgreSQL text search weights:
Args: field - Field keyword (:name, :email, etc.) config - Configuration map with :weights
Returns: Float weight (0.1-1.0)
Example: (calculate-field-weight :name {:weights {:name 'A}}) ;=> 1.0
(calculate-field-weight :bio {:weights {:bio 'C}}) ;=> 0.2
Pure: true
Calculate weight for field based on configuration.
PostgreSQL text search weights:
- 'A: 1.0 (highest weight - titles, names)
- 'B: 0.4 (medium-high - emails, summaries)
- 'C: 0.2 (medium - descriptions, content)
- 'D: 0.1 (lowest - metadata, tags)
Args:
field - Field keyword (:name, :email, etc.)
config - Configuration map with :weights
Returns:
Float weight (0.1-1.0)
Example:
(calculate-field-weight :name {:weights {:name 'A}})
;=> 1.0
(calculate-field-weight :bio {:weights {:bio 'C}})
;=> 0.2
Pure: true(calculate-median-score results)Calculate median score across results.
Args: results - List of result maps with :score
Returns: Median score (float)
Example: (calculate-median-score [{:score 0.8} {:score 0.6} {:score 0.4}]) ;=> 0.6
Pure: true
Calculate median score across results.
Args:
results - List of result maps with :score
Returns:
Median score (float)
Example:
(calculate-median-score [{:score 0.8} {:score 0.6} {:score 0.4}])
;=> 0.6
Pure: true(combine-scores scores weights)Combine multiple scores with weights.
Useful for combining text relevance, recency, popularity, etc.
Args: scores - Map of score-name->value {:relevance 0.8 :recency 0.6 :popularity 0.9} weights - Map of score-name->weight {:relevance 0.6 :recency 0.2 :popularity 0.2}
Returns: Combined score (weighted average)
Example: (combine-scores {:relevance 0.8 :recency 0.5} {:relevance 0.7 :recency 0.3}) ;=> 0.71
Pure: true
Combine multiple scores with weights.
Useful for combining text relevance, recency, popularity, etc.
Args:
scores - Map of score-name->value
{:relevance 0.8 :recency 0.6 :popularity 0.9}
weights - Map of score-name->weight
{:relevance 0.6 :recency 0.2 :popularity 0.2}
Returns:
Combined score (weighted average)
Example:
(combine-scores {:relevance 0.8 :recency 0.5}
{:relevance 0.7 :recency 0.3})
;=> 0.71
Pure: true(deduplicate-by-field results field)Remove duplicate results based on field value.
Keeps first occurrence of each unique value.
Args: results - List of result maps field - Field to deduplicate by
Returns: Deduplicated results
Example: (deduplicate-by-field [{:id 1 :name "John"} {:id 2 :name "Jane"} {:id 3 :name "John"}] :name) ;=> [{:id 1 :name "John"} {:id 2 :name "Jane"}]
Pure: true
Remove duplicate results based on field value.
Keeps first occurrence of each unique value.
Args:
results - List of result maps
field - Field to deduplicate by
Returns:
Deduplicated results
Example:
(deduplicate-by-field [{:id 1 :name "John"}
{:id 2 :name "Jane"}
{:id 3 :name "John"}]
:name)
;=> [{:id 1 :name "John"} {:id 2 :name "Jane"}]
Pure: true(diversify-results results field max-per-value)Diversify results by field (reduce over-representation).
Ensures results are diverse by limiting how many results can have the same field value.
Args: results - Sorted list of results field - Field to diversify by (e.g., :category, :author) max-per-value - Maximum results per unique value
Returns: Diversified results
Example: (diversify-results [{:category "tech" :score 0.9} {:category "tech" :score 0.8} {:category "tech" :score 0.7} {:category "sports" :score 0.6}] :category 2) ;=> First 2 tech results + sports result
Pure: true
Diversify results by field (reduce over-representation).
Ensures results are diverse by limiting how many results
can have the same field value.
Args:
results - Sorted list of results
field - Field to diversify by (e.g., :category, :author)
max-per-value - Maximum results per unique value
Returns:
Diversified results
Example:
(diversify-results [{:category "tech" :score 0.9}
{:category "tech" :score 0.8}
{:category "tech" :score 0.7}
{:category "sports" :score 0.6}]
:category
2)
;=> First 2 tech results + sports result
Pure: true(multiply-scores scores)Multiply scores together (useful for boolean scoring).
Args: scores - Collection of scores
Returns: Product of all scores
Example: (multiply-scores [0.8 0.9 0.7]) ;=> 0.504
Pure: true
Multiply scores together (useful for boolean scoring). Args: scores - Collection of scores Returns: Product of all scores Example: (multiply-scores [0.8 0.9 0.7]) ;=> 0.504 Pure: true
(normalize-field-weights weights)Normalize field weights to sum to 1.0.
Useful when combining scores from multiple fields.
Args: weights - Map of field->weight
Returns: Map of field->normalized-weight
Example: (normalize-field-weights {:name 1.0 :email 0.4 :bio 0.2}) ;=> {:name 0.625 :email 0.25 :bio 0.125}
Pure: true
Normalize field weights to sum to 1.0.
Useful when combining scores from multiple fields.
Args:
weights - Map of field->weight
Returns:
Map of field->normalized-weight
Example:
(normalize-field-weights {:name 1.0 :email 0.4 :bio 0.2})
;=> {:name 0.625 :email 0.25 :bio 0.125}
Pure: true(normalize-scores results)Normalize scores to 0-1 range using min-max normalization.
Args: results - List of result maps with :score
Returns: Results with added :normalized-score field
Example: (normalize-scores [{:id 1 :score 0.8} {:id 2 :score 0.5} {:id 3 :score 0.3}]) ;=> [{:id 1 :score 0.8 :normalized-score 1.0} ; {:id 2 :score 0.5 :normalized-score 0.4} ; {:id 3 :score 0.3 :normalized-score 0.0}]
Pure: true
Normalize scores to 0-1 range using min-max normalization.
Args:
results - List of result maps with :score
Returns:
Results with added :normalized-score field
Example:
(normalize-scores [{:id 1 :score 0.8}
{:id 2 :score 0.5}
{:id 3 :score 0.3}])
;=> [{:id 1 :score 0.8 :normalized-score 1.0}
; {:id 2 :score 0.5 :normalized-score 0.4}
; {:id 3 :score 0.3 :normalized-score 0.0}]
Pure: true(normalize-scores-zscore results)Normalize scores using z-score standardization.
Z-score normalization: (score - mean) / stddev Results in mean=0, stddev=1 distribution.
Args: results - List of result maps with :score
Returns: Results with added :z-score field
Example: (normalize-scores-zscore [{:id 1 :score 0.8} {:id 2 :score 0.5} {:id 3 :score 0.3}])
Pure: true
Normalize scores using z-score standardization.
Z-score normalization: (score - mean) / stddev
Results in mean=0, stddev=1 distribution.
Args:
results - List of result maps with :score
Returns:
Results with added :z-score field
Example:
(normalize-scores-zscore [{:id 1 :score 0.8}
{:id 2 :score 0.5}
{:id 3 :score 0.3}])
Pure: true(rank-by-field results field direction)Rank results by field value.
Args: results - List of result maps field - Field to sort by direction - :asc or :desc
Returns: Sorted results
Example: (rank-by-field [{:name "Zoe"} {:name "Alice"}] :name :asc) ;=> [{:name "Alice"} {:name "Zoe"}]
Pure: true
Rank results by field value.
Args:
results - List of result maps
field - Field to sort by
direction - :asc or :desc
Returns:
Sorted results
Example:
(rank-by-field [{:name "Zoe"} {:name "Alice"}] :name :asc)
;=> [{:name "Alice"} {:name "Zoe"}]
Pure: true(rank-results results)Rank results by score (highest first).
Args: results - List of result maps with :score
Returns: Results sorted by score descending (as vector)
Example: (rank-results [{:id 1 :score 0.5} {:id 2 :score 0.9} {:id 3 :score 0.7}]) ;=> [{:id 2 :score 0.9} ; {:id 3 :score 0.7} ; {:id 1 :score 0.5}]
Pure: true
Rank results by score (highest first).
Args:
results - List of result maps with :score
Returns:
Results sorted by score descending (as vector)
Example:
(rank-results [{:id 1 :score 0.5}
{:id 2 :score 0.9}
{:id 3 :score 0.7}])
;=> [{:id 2 :score 0.9}
; {:id 3 :score 0.7}
; {:id 1 :score 0.5}]
Pure: truecljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |