diff --git a/README.md b/README.md index 3ad5e8d..09039d2 100644 --- a/README.md +++ b/README.md @@ -280,6 +280,13 @@ You can also change the edit distance with: Product.search "zucini", misspellings: {edit_distance: 2} # zucchini ``` +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: + +```ruby +Product.search "zuccihni", misspellings: {transpositions: true} # zucchini +``` + + ### Indexing Control what data is indexed with the `search_data` method. Call `Product.reindex` after changing this method. diff --git a/lib/searchkick/query.rb b/lib/searchkick/query.rb index a1b65bd..bce1664 100644 --- a/lib/searchkick/query.rb +++ b/lib/searchkick/query.rb @@ -107,9 +107,10 @@ module Searchkick misspellings = options.key?(:misspellings) ? options[:misspellings] : options[:mispellings] # why not? if misspellings != false edit_distance = (misspellings.is_a?(Hash) && (misspellings[:edit_distance] || misspellings[:distance])) || 1 + transpositions = (misspellings.is_a?(Hash) && misspellings[:transpositions] == true) ? {fuzzy_transpositions: true} : {} qs.concat [ - shared_options.merge(fuzziness: edit_distance, max_expansions: 3, analyzer: "searchkick_search"), - shared_options.merge(fuzziness: edit_distance, max_expansions: 3, analyzer: "searchkick_search2") + shared_options.merge(fuzziness: edit_distance, max_expansions: 3, analyzer: "searchkick_search").merge(transpositions), + shared_options.merge(fuzziness: edit_distance, max_expansions: 3, analyzer: "searchkick_search2").merge(transpositions) ] end elsif field.end_with?(".exact") diff --git a/test/match_test.rb b/test/match_test.rb index 0dad347..7469dcd 100644 --- a/test/match_test.rb +++ b/test/match_test.rb @@ -112,6 +112,27 @@ class TestMatch < Minitest::Test assert_search "zip lock", ["Ziploc"] end + def test_misspelling_zucchini_transposition + store_names ["zucchini"] + assert_search "zuccihni", [] # doesn't work without transpositions:true option + assert_search "zuccihni", ["zucchini"], misspellings: {transpositions: true} + end + + def test_misspelling_lasagna + store_names ["lasagna"] + assert_search "lasanga", ["lasagna"], misspellings: {transpositions: true} + assert_search "lasgana", ["lasagna"], misspellings: {transpositions: true} + assert_search "lasaang", [], misspellings: {transpositions: true} # triple transposition, shouldn't work + assert_search "lsagana", [], misspellings: {transpositions: true} # triple transposition, shouldn't work + end + + def test_misspelling_lasagna_pasta + store_names ["lasagna pasta"] + assert_search "lasanga", ["lasagna pasta"], misspellings: {transpositions: true} + assert_search "lasanga pasta", ["lasagna pasta"], misspellings: {transpositions: true} + assert_search "lasanga pasat", ["lasagna pasta"], misspellings: {transpositions: true} # both words misspelled with a transposition should still work + end + # spaces def test_spaces_in_field -- libgit2 0.21.0