Commit f151d404755236b5532b90cb162f862292c10d55
1 parent
de39f792
Exists in
master
and in
21 other branches
add support for fuzzy transpositions
Showing
3 changed files
with
31 additions
and
2 deletions
Show diff stats
README.md
@@ -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 |