Class: Autoselect::Otu::Levels::Fast
- Defined in:
- lib/autoselect/otu/levels/fast.rb
Overview
Fast level: prefix-only match via a single LEFT JOIN query; no GIN, no similarity. Covers three patterns in one round-trip:
1. Otu#name (taxon_name_id IS NULL) — exact or prefix
2. TaxonName#cached — exact or prefix
3. Multi-word hybrid — every possible split of the term into a
(taxon_prefix, otu_part) pair; both halves use prefix matching so
'P PE01' matches 'Pheidole' + 'PE01', 'Ph PE01' also matches, etc.
All split points are OR'd into the same query (one round-trip).
Ordering: shorter coalesced name first (exact matches float up over prefix matches); standalone OTUs use Otu#name length; then shorter Otu#name as tiebreaker.
Constant Summary
Constants inherited from Level
Level::DEFAULT_FUSE_MS, Level::EXTERNAL_FUSE_MS, Level::MINIMUM_RESULTS
Instance Method Summary collapse
- #call(term:, operator: nil, project_id: nil, user_id: nil, **_kwargs) ⇒ Array<Otu>
- #description ⇒ Object
- #key ⇒ Object
- #label ⇒ Object
Methods inherited from Level
#external?, #fuse_ms, #metadata, #minimum_results, #model_key, #record_info, #record_info_html, #record_label, #record_label_html
Instance Method Details
#call(term:, operator: nil, project_id: nil, user_id: nil, **_kwargs) ⇒ Array<Otu>
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/autoselect/otu/levels/fast.rb', line 33 def call(term:, operator: nil, project_id: nil, user_id: nil, **_kwargs) return [] if term.blank? sanitized = ::ApplicationRecord.sanitize_sql_like(term) o = ::Otu.arel_table tn = ::TaxonName.arel_table # Pattern 1 — standalone OTU name (no taxon_name attachment) p1 = o[:taxon_name_id].eq(nil).and( o[:name].eq(term).or(o[:name].matches("#{sanitized}%")) ) # Pattern 2 — OTU backed by a TaxonName whose cached column matches p2 = tn[:cached].eq(term).or(tn[:cached].matches("#{sanitized}%")) conditions = p1.or(p2) # Pattern 3 — multi-word hybrid: try every split point so that both # short abbreviations ('P PE01') and longer prefixes ('Phei PE01') work. # The taxon half uses a prefix match; the OTU half uses exact-or-prefix. words = term.split(' ') if words.length >= 2 hybrid = (1...words.length).map do |i| taxon_part = words[0, i].join(' ') otu_part = words[i..].join(' ') s_taxon = ::ApplicationRecord.sanitize_sql_like(taxon_part) s_otu = ::ApplicationRecord.sanitize_sql_like(otu_part) tn[:cached].matches("#{s_taxon}%").and( o[:name].eq(otu_part).or(o[:name].matches("#{s_otu}%")) ) end.reduce(:or) conditions = conditions.or(hybrid) end scope = ::Otu.eager_load(:taxon_name).where(conditions) scope = scope.where(project_id:) if project_id.present? # Shorter coalesced name = closer to exact match; standalone OTUs fall back to otus.name. scope = scope.order( Arel.sql('length(coalesce(taxon_names.cached, otus.name, \'\')) asc nulls last, length(coalesce(otus.name, \'\')) asc nulls last') ) scope.limit(20).to_a end |
#description ⇒ Object
26 27 28 |
# File 'lib/autoselect/otu/levels/fast.rb', line 26 def description 'Prefix match on OTU name and linked taxon name cached (no fuzzy matching)' end |
#key ⇒ Object
18 19 20 |
# File 'lib/autoselect/otu/levels/fast.rb', line 18 def key :fast end |
#label ⇒ Object
22 23 24 |
# File 'lib/autoselect/otu/levels/fast.rb', line 22 def label 'Fast' end |