JavaScript模糊搜索

Ion*_*icu 9 javascript fuzzy-search

我正在研究这个过滤的东西,我有大约50-100个列表项.每个项目都有这样的标记:

<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>
Run Code Online (Sandbox Code Playgroud)

我创建了这样的标记因为我最初使用了List.js

所以,可能你已经猜到了,我想要的是做这样的搜索:@region: LA @price: 124等等.问题是我还想显示多个项目,以便选择超过......一个:)

我认为这需要模糊搜索,但问题是我找不到任何功能.

任何想法或起点?

//编辑:因为我有相当少量的项目,我想要一个客户端解决方案.

Dzi*_*owy 27

我在javascript中寻找"模糊搜索",但是在这里找不到解决方案,所以我编写了自己的功能来完成我需要的工作.

该算法非常简单:循环通过针头字母并检查它们是否在大海捞针中以相同的顺序出现:

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;
};
Run Code Online (Sandbox Code Playgroud)

例如:

('a haystack with a needle').fuzzy('hay sucks');    // false
('a haystack with a needle').fuzzy('sack hand');    // true
Run Code Online (Sandbox Code Playgroud)

  • 这很简洁(除了字符串原型操作),并且适合某些用例,但更复杂的模糊搜索还需要返回最相关的结果。我想这将基于连续的字符数。 (2认同)

Ion*_*icu 6

一年后,List.js得到了一个很好的模糊搜索插件,效果非常好.

  • 它进行搜索,但它不是真正的"模糊搜索".例如在他们的演示"模糊"查询中:"bruwo"没有找到"Guybrush Threepwood"...... (2认同)

Mar*_*ren 5

我对 list.js 不满意,所以我创建了自己的。这可能不完全是模糊搜索,但我不知道该怎么称呼它。我只是希望它匹配查询,而不考虑查询中单词的顺序。

考虑以下场景:

  • 内存中存在文章集合
  • 查询词出现的顺序并不重要(例如“hello world”与“world hello”)
  • 代码应该易于阅读

这是一个例子:

var articles = [{
  title: '2014 Javascript MVC Frameworks Comparison',
  author: 'Guybrush Treepwood'
}, {
  title: 'Javascript in the year 2014',
  author: 'Herman Toothrot'
},
{
  title: 'Javascript in the year 2013',
  author: 'Rapp Scallion'
}];

var fuzzy = function(items, key) {
  // Returns a method that you can use to create your own reusable fuzzy search.

  return function(query) {
    var words  = query.toLowerCase().split(' ');

    return items.filter(function(item) {
      var normalizedTerm = item[key].toLowerCase();

      return words.every(function(word) {
        return (normalizedTerm.indexOf(word) > -1);
      });
    });
  };
};


var searchByTitle = fuzzy(articles, 'title');

searchByTitle('javascript 2014') // returns the 1st and 2nd items
Run Code Online (Sandbox Code Playgroud)

好吧,我希望这对那里的人有帮助。


gnj*_*gnj 5

另一个(简单的)解决方案。不区分大小写并忽略字母顺序。

它对搜索词的每个字母进行检查。如果原始字符串包含该字母,它将向上计数(如果不包含则向下计数)。根据匹配/字符串长度的比率,它将返回 true 或 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 == "")
};
Run Code Online (Sandbox Code Playgroud)

例子:

("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)
Run Code Online (Sandbox Code Playgroud)