krisk / Fuse

Lightweight fuzzy-search, in JavaScript
https://fusejs.io/
Apache License 2.0
17.76k stars 753 forks source link

$for = fuzzy $or operator #688

Closed fusionbeam closed 1 year ago

fusionbeam commented 1 year ago

Description

A clear and concise description of the problem or missing capability.. There is a need to perform a search where all query terms occurrences improve the overall matching score. I.e when searching for a product by a set of terms it is quite intuitive that the more relevant product is the one with the most terms occurring in its title or product description or wherever. ### Describe the solution you'd like A fuzzy $or operator that is not Boolean logic but a fuzzy one that is additive (cumulative). That is each occurrence of query term increases the overall score of the document in the search result. ### Describe alternatives you've considered $and operator is too restrictive, it requires all terms to occur $or operator is ordering results in accordance with the number of occurrences
fusionbeam commented 1 year ago

This is the code and it shows that multiple occurrences are not recorded and don't improve the score. Matches are reset before iterating the next query term.


// ORs
    for (let i = 0, qLen = query.length; i < qLen; i += 1) {
      const searchers = query[i];

      // Reset indices
      allIndices.length = 0;
      numMatches = 0;

      // ANDs
      for (let j = 0, pLen = searchers.length; j < pLen; j += 1) {
        const searcher = searchers[j];
        const { isMatch, indices, score } = searcher.search(text);

        if (isMatch) {
          numMatches += 1;
          totalScore += score;
          if (includeMatches) {
            const type = searcher.constructor.type;
            if (MultiMatchSet.has(type)) {
              allIndices = [...allIndices, ...indices];
            } else {
              allIndices.push(indices);
            }
          }
        } else {
          totalScore = 0;
          numMatches = 0;
          allIndices.length = 0;
          break
        }
      }

      // OR condition, so if TRUE, return
      if (numMatches) {
        let result = {
          isMatch: true,
          score: totalScore / numMatches
        };

        if (includeMatches) {
          result.indices = allIndices;
        }

        return result
      }
    }
fusionbeam commented 1 year ago

for product searches being able to get better score for multiple occurrences is very important.

github-actions[bot] commented 1 year ago

This issue is stale because it has been open 120 days with no activity. Remove stale label or comment or this will be closed in 30 days