Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript fuzzy search

I'm working on this filtering thing where I have about 50-100 list items. And each items have markup like this:

<li>
  <input type="checkbox" name="services[]" value="service_id" />
  <span class="name">Restaurant in NY</span>
  <span class="filters"><!-- hidden area -->
    <span class="city">@city: new york</span>
    <span class="region">@reg: ny</span>
    <span class="date">@start: 02/05/2012</span>
    <span class="price">@price: 100</span>
  </span>
</li>

I created markup like this because I initally used List.js

So, probably you guessed already, what I want is to do searches like this:@region: LA @price: 124 and so on. The problem is that i also want to display more than one item, in order to select more than... one :)

I assume this needs fuzzy search, but the problem is that i didn't find anything functional.

Any idea or starting point?

// edit: because I have a fairly small amount of items, I would like a client side solution.

like image 456
Ionuț Staicu Avatar asked Feb 09 '12 05:02

Ionuț Staicu


People also ask

What is fuzzy search JavaScript?

Fuzzy searching matches the meaning, not necessarily the precise wording or specified phrases. It performs something the same as full-text search against data to see likely misspellings and approximate string matching.

What is fuzzy search?

A fuzzy search searches for text that matches a term closely instead of exactly. Fuzzy searches help you find relevant results even when the search terms are misspelled. To perform a fuzzy search, append a tilde (~) at the end of the search term.

What is Fusejs?

Fuse. js is a JavaScript library that provides fuzzy search capabilities for applications and websites. It's nice and easy to use out of the box, but also includes configuration options that allow you to tweak and create powerful solutions.


2 Answers

Another (simple) solution. Non case-sensitive and ignores order of the letters.

It performs a check for every letter of the search-term. If the original string contains that letter, it will count up (or down if it doesn't). Based on the ratio of matches / string-length it will return true or false.

String.prototype.fuzzy = function(term, ratio) {
    var string = this.toLowerCase();
    var compare = term.toLowerCase();
    var matches = 0;
    if (string.indexOf(compare) > -1) return true; // covers basic partial matches
    for (var i = 0; i < compare.length; i++) {
        string.indexOf(compare[i]) > -1 ? matches += 1 : matches -=1;
    }
    return (matches/this.length >= ratio || term == "")
};

Examples:

("Test").fuzzy("st", 0.5) // returns true
("Test").fuzzy("tes", 0.8) // returns false cause ratio is too low (0.75)
("Test").fuzzy("stet", 1) // returns true
("Test").fuzzy("zzzzzest", 0.75) // returns false cause too many alien characters ("z")
("Test").fuzzy("es", 1) // returns true cause partial match (despite ratio being only 0.5)
like image 135
gnj Avatar answered Nov 15 '22 12:11

gnj


I was looking for "fuzzy search" in javascript but haven't found a solution here, so I wrote my own function that does what I need.

The algorithm is very simple: loop through needle letters and check if they occur in the same order in the haystack:

String.prototype.fuzzy = function (s) {
    var hay = this.toLowerCase(), i = 0, n = -1, l;
    s = s.toLowerCase();
    for (; l = s[i++] ;) if (!~(n = hay.indexOf(l, n + 1))) return false;
    return true;
};

e.g.:

('a haystack with a needle').fuzzy('hay sucks');    // false
('a haystack with a needle').fuzzy('sack hand');    // true
like image 21
Dziad Borowy Avatar answered Nov 15 '22 13:11

Dziad Borowy