Module: OKF::Bundle::Search::Index

Defined in:
lib/okf/bundle/search/index.rb

Overview

The default engine: a MiniFTS full-text index — the same engine, and the same BM25+ arithmetic, the browser page already runs as MiniSearch, so a Ruby-built index and the page's rank identically.

Matching is by token: a term matches a whole word or a word it prefixes ("dedup" reaches "deduplication"), and fuzzy: opts into typo tolerance. The index builds per call unless the caller holds a Search::Corpus, which builds it once through .prepare and reuses it — the server does, the one-shot CLI cannot. See .okf/capabilities/search.md.

Constant Summary collapse

CAPABILITIES =
%i[fuzzy prefix].freeze

Class Method Summary collapse

Class Method Details

.available?Boolean

minifts is a hard runtime dependency with no native extension, so it is here whenever the gem is. An addon backed by a native build is the case this predicate exists for.

Returns:

  • (Boolean)


33
34
35
# File 'lib/okf/bundle/search/index.rb', line 33

def available?
  true
end

.call(documents, terms, fields:, fuzzy: false, prepared: nil, **_options) ⇒ Object



51
52
53
54
55
56
57
58
59
60
# File 'lib/okf/bundle/search/index.rb', line 51

def call(documents, terms, fields:, fuzzy: false, prepared: nil, **_options)
  index = prepared || prepare(documents)

  options = { combine_with: "AND", prefix: true, boost: WEIGHTS, fields: fields }
  options[:fuzzy] = FUZZY_DISTANCE if fuzzy

  index.search(terms.join(" "), options).map do |hit|
    { key: hit[:id], matched: matched_in(hit), score: hit[:score], terms: hit[:terms] }
  end
end

.capabilitiesObject



26
27
28
# File 'lib/okf/bundle/search/index.rb', line 26

def capabilities
  CAPABILITIES
end

.idObject



22
23
24
# File 'lib/okf/bundle/search/index.rb', line 22

def id
  :index
end

.prepare(documents) ⇒ Object

fields: narrows where a term may hit, so a field the caller excluded can neither match nor be credited. The hit's terms are MiniFTS's matched document terms — already lowercased, and present in the text verbatim even when the query only prefixed them. The expensive half, separated so a long-lived caller can hold it. A Corpus calls this once; a one-shot call still goes through #call and builds inline, which is why this is an addition and not a new requirement on the engine contract.



45
46
47
48
49
# File 'lib/okf/bundle/search/index.rb', line 45

def prepare(documents)
  index = MiniFTS.new(fields: FIELDS, id_field: "key")
  index.add_all(documents)
  index
end