Commit f151d404755236b5532b90cb162f862292c10d55

Authored by Rajesh Kumar
1 parent de39f792

add support for fuzzy transpositions

@@ -280,6 +280,13 @@ You can also change the edit distance with: @@ -280,6 +280,13 @@ You can also change the edit distance with:
280 Product.search "zucini", misspellings: {edit_distance: 2} # zucchini 280 Product.search "zucini", misspellings: {edit_distance: 2} # zucchini
281 ``` 281 ```
282 282
  283 +A transposition of two letters is considered to be an edit distance of 2. Enable single-letter transpositions while leaving edit distance at 1 with:
  284 +
  285 +```ruby
  286 +Product.search "zuccihni", misspellings: {transpositions: true} # zucchini
  287 +```
  288 +
  289 +
283 ### Indexing 290 ### Indexing
284 291
285 Control what data is indexed with the `search_data` method. Call `Product.reindex` after changing this method. 292 Control what data is indexed with the `search_data` method. Call `Product.reindex` after changing this method.
lib/searchkick/query.rb
@@ -107,9 +107,10 @@ module Searchkick @@ -107,9 +107,10 @@ module Searchkick
107 misspellings = options.key?(:misspellings) ? options[:misspellings] : options[:mispellings] # why not? 107 misspellings = options.key?(:misspellings) ? options[:misspellings] : options[:mispellings] # why not?
108 if misspellings != false 108 if misspellings != false
109 edit_distance = (misspellings.is_a?(Hash) && (misspellings[:edit_distance] || misspellings[:distance])) || 1 109 edit_distance = (misspellings.is_a?(Hash) && (misspellings[:edit_distance] || misspellings[:distance])) || 1
  110 + transpositions = (misspellings.is_a?(Hash) && misspellings[:transpositions] == true) ? {fuzzy_transpositions: true} : {}
110 qs.concat [ 111 qs.concat [
111 - shared_options.merge(fuzziness: edit_distance, max_expansions: 3, analyzer: "searchkick_search"),  
112 - shared_options.merge(fuzziness: edit_distance, max_expansions: 3, analyzer: "searchkick_search2") 112 + shared_options.merge(fuzziness: edit_distance, max_expansions: 3, analyzer: "searchkick_search").merge(transpositions),
  113 + shared_options.merge(fuzziness: edit_distance, max_expansions: 3, analyzer: "searchkick_search2").merge(transpositions)
113 ] 114 ]
114 end 115 end
115 elsif field.end_with?(".exact") 116 elsif field.end_with?(".exact")
test/match_test.rb
@@ -112,6 +112,27 @@ class TestMatch < Minitest::Test @@ -112,6 +112,27 @@ class TestMatch < Minitest::Test
112 assert_search "zip lock", ["Ziploc"] 112 assert_search "zip lock", ["Ziploc"]
113 end 113 end
114 114
  115 + def test_misspelling_zucchini_transposition
  116 + store_names ["zucchini"]
  117 + assert_search "zuccihni", [] # doesn't work without transpositions:true option
  118 + assert_search "zuccihni", ["zucchini"], misspellings: {transpositions: true}
  119 + end
  120 +
  121 + def test_misspelling_lasagna
  122 + store_names ["lasagna"]
  123 + assert_search "lasanga", ["lasagna"], misspellings: {transpositions: true}
  124 + assert_search "lasgana", ["lasagna"], misspellings: {transpositions: true}
  125 + assert_search "lasaang", [], misspellings: {transpositions: true} # triple transposition, shouldn't work
  126 + assert_search "lsagana", [], misspellings: {transpositions: true} # triple transposition, shouldn't work
  127 + end
  128 +
  129 + def test_misspelling_lasagna_pasta
  130 + store_names ["lasagna pasta"]
  131 + assert_search "lasanga", ["lasagna pasta"], misspellings: {transpositions: true}
  132 + assert_search "lasanga pasta", ["lasagna pasta"], misspellings: {transpositions: true}
  133 + assert_search "lasanga pasat", ["lasagna pasta"], misspellings: {transpositions: true} # both words misspelled with a transposition should still work
  134 + end
  135 +
115 # spaces 136 # spaces
116 137
117 def test_spaces_in_field 138 def test_spaces_in_field