Class: OKF::Bundle::Search
- Inherits:
-
Object
- Object
- OKF::Bundle::Search
- Defined in:
- lib/okf/bundle/search.rb
Overview
Deterministic text retrieval over an in-memory bundle — the browser page's
search brought server-side and extended to bodies. Terms are ANDed: every
term must hit at least one searched field, though not necessarily the same
one. A term is a case-insensitive substring, or a Ruby regular expression
with regexp: true. Matches rank by where they hit (a title hit outranks a
body hit) and carry one bounded context snippet, so answering "which concept
covers X?" costs a row, not a body read.
Deliberately not fuzzy: the consuming agent is the fuzzy layer — synonyms and vocabulary drift are judgment over the index map, not string distance.
Pure — no disk, no stdio. The CLI's okf search and any embedding app share
it: OKF::Bundle::Search.call(bundle, [ "dedup", "key" ]).
Constant Summary collapse
- WEIGHTS =
The searchable fields with their rank weight, strongest signal first. A concept's score sums the weights of the fields that matched; hitting a field twice does not stack. Tags match against the space-joined list, mirroring the server page's haystack.
{ "title" => 5, "id" => 4, "tags" => 3, "type" => 2, "description" => 2, "body" => 1 }.freeze
- FIELDS =
WEIGHTS.keys.freeze
- SNIPPET_FIELDS =
Fields whose match is only meaningful with surrounding context. The other fields already appear whole on the result row.
%w[description body].freeze
- SNIPPET_RADIUS =
Characters of context kept on each side of the first matched term.
44
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(bundle, terms, fields: nil, regexp: false) ⇒ Search
constructor
Raises RegexpError on an invalid pattern with
regexp: true— the caller owns turning that into a usage error. -
#results ⇒ Object
Ranked match rows, catalog-style identity plus where the terms hit: [{ id:, title:, type:, area:, tags:, matched: [field, …], score:, snippet: }, …] ordered by score descending, then id.
Constructor Details
#initialize(bundle, terms, fields: nil, regexp: false) ⇒ Search
Raises RegexpError on an invalid pattern with regexp: true — the caller
owns turning that into a usage error.
47 48 49 50 51 52 |
# File 'lib/okf/bundle/search.rb', line 47 def initialize(bundle, terms, fields: nil, regexp: false) @bundle = bundle raw = Array(terms).reject { |term| OKF.blank?(term) } @matchers = raw.map { |term| regexp ? Regexp.new(term.to_s, Regexp::IGNORECASE) : term.to_s.downcase } @fields = fields.nil? || fields.empty? ? FIELDS : fields end |
Class Method Details
.call(bundle, terms, fields: nil, regexp: false) ⇒ Object
41 42 43 |
# File 'lib/okf/bundle/search.rb', line 41 def self.call(bundle, terms, fields: nil, regexp: false) new(bundle, terms, fields: fields, regexp: regexp).results end |
Instance Method Details
#results ⇒ Object
Ranked match rows, catalog-style identity plus where the terms hit: [{ id:, title:, type:, area:, tags:, matched: [field, …], score:, snippet: }, …] ordered by score descending, then id. No terms means no matches.
57 58 59 60 61 62 63 64 |
# File 'lib/okf/bundle/search.rb', line 57 def results return [] if @matchers.empty? @bundle.concepts .map { |concept| match(concept) } .compact .sort_by { |row| [ -row[:score], row[:id] ] } end |