class GraphedFuzzySearch::Collection

Attributes

attributes[R]
different_token_weight[R]
normal_weight[R]
objects[R]
token_regex[R]

Public Class Methods

new(objects, attributes: [:to_s], token_regex: DEFAULT_TOKEN_REGEX, normal_weight: 1, different_token_weight: 5) click to toggle source
# File lib/graphed_fuzzy_search.rb, line 11
def initialize(objects, attributes: [:to_s], token_regex: DEFAULT_TOKEN_REGEX, normal_weight: 1, different_token_weight: 5)
  @objects = objects
  @attributes = attributes
  @token_regex = token_regex
  @normal_weight = normal_weight
  @different_token_weight = different_token_weight
  trees
end

Public Instance Methods

inspect() click to toggle source
# File lib/graphed_fuzzy_search.rb, line 20
def inspect
  "#<#{self.class.name}>"
end
items() click to toggle source
# File lib/graphed_fuzzy_search.rb, line 52
def items
  @items ||= objects.map do |obj|
    attrs = attributes.flat_map do |k|
      [*obj.send(k)]
    end
    tokens = attrs.flat_map do |attr|
      attr.to_s.downcase.scan(token_regex)
    end
    tokens.push(*attrs)
    tokens.reject!(&:empty?)
    Item.new(obj, attrs[0], tokens.uniq)
  end
end
query(*args, **kwargs) click to toggle source
# File lib/graphed_fuzzy_search.rb, line 27
def query(*args, **kwargs)
  query_raw(*args, **kwargs).map{ |(node, _)| node.item.object }
end
query_raw(str, max_scan: str.size) click to toggle source
# File lib/graphed_fuzzy_search.rb, line 31
def query_raw(str, max_scan: str.size)
  str = str.downcase
  chars = str.chars
  i = 0
  needles = trees.map { |root| [root, 0] }
  while i < chars.size && i < max_scan && !needles.empty?
    char = chars[i]
    needles.map! { |(node, weight)| [node[char], weight] }
    needles.select!(&:first)
    needles.map! { |(conn, weight)| [conn.node, weight + conn.weight] }
    i += 1
  end
  needles.map! { |(conn, weight)|
    if conn.item.key.start_with?(str)
      weight *= 0.7
    end
    [conn, weight]
  }
  needles.sort_by(&:last)
end
trees() click to toggle source
# File lib/graphed_fuzzy_search.rb, line 66
def trees
  @trees ||= items.map do |item|
    root = Node.new(nil, [], item)
    token_and_heads = item.tokens.map do |token|
      root.mine(normal_weight, token)
      [token, root[token[0]].node]
    end
    token_and_heads.each do |(_, ah)|
      token_and_heads.each do |(bt, _)|
        root.walk(bt.each_char) do |n|
          n.connect(different_token_weight, ah)
        end
      end
    end
    root
  end
end