For performance reasons, when fuzzy search was introduces it was decided to limit the number of records used for finding fuzzy terms to 1000. Because of this, when a database contains more than 1000 products matching words that start with the same letter, further products are not examined. This can lead to searches not finding an existing exact match. This commit introduces a fallback mechanism so that, if we are in a situation where the maximum number of examined records was fetched, we also explicitly check for a possible exact match across all records. Steps to reproduce: - Do not install the pg_trgm extension. - Have more than 1000 products containing searchable words (name, description...) starting with the same letter. - Add one more such product (so that it is not in the 1000 first ones). - Search for that last product by correctly typing the word. => Exact match was not returned. task-2870947 closes odoo/odoo#97657 X-original-commit: 6d24ea28b236155d542e3d2be3da379b9f4e9ce6 Signed-off-by: Romain Derie (rde) <rde@odoo.com>
75 lines
3.2 KiB
Python
75 lines
3.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import logging
|
|
|
|
from odoo.addons.website.controllers.main import Website
|
|
from odoo.addons.website.tools import MockRequest
|
|
import odoo.tests
|
|
from odoo.tests.common import TransactionCase
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
@odoo.tests.tagged('-at_install', 'post_install')
|
|
class TestAutoComplete(TransactionCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.website = cls.env['website'].browse(1)
|
|
cls.WebsiteController = Website()
|
|
|
|
def _autocomplete(self, term, expected_count, expected_fuzzy_term):
|
|
""" Calls the autocomplete for a given term and performs general checks """
|
|
with MockRequest(self.env, website=self.website):
|
|
suggestions = self.WebsiteController.autocomplete(
|
|
search_type="test", term=term, max_nb_chars=50, options={},
|
|
)
|
|
self.assertEqual(expected_count, suggestions['results_count'], "Wrong number of suggestions")
|
|
self.assertEqual(expected_fuzzy_term, suggestions.get('fuzzy_search', 'Not found'), "Wrong fuzzy match")
|
|
|
|
def test_01_many_records(self):
|
|
# REF1000~REF3999
|
|
data = [{
|
|
'name': 'REF%s' % count,
|
|
'is_published': True,
|
|
} for count in range(1000, 4000)]
|
|
self.env['test.model'].create(data)
|
|
# NUM1000~NUM1998
|
|
data = [{
|
|
'name': 'NUM%s' % count,
|
|
'is_published': True,
|
|
} for count in range(1000, 1999)]
|
|
self.env['test.model'].create(data)
|
|
# There are more than 1000 "R*" records
|
|
# => Find exact match through the fallback
|
|
self._autocomplete('REF3000', 1, False)
|
|
# => No exact match => Find fuzzy within first 1000 (distance=3: replace D by F, move 3, add 1)
|
|
self._autocomplete('RED3000', 1, 'ref1003')
|
|
# => Find exact match through the fallback
|
|
self._autocomplete('REF300', 10, False)
|
|
# => Find exact match through the fallback
|
|
self._autocomplete('REF1', 1000, False)
|
|
# => No exact match => Nothing close enough (min distance=5)
|
|
self._autocomplete('REFX', 0, "Not found")
|
|
# => Find exact match through the fallback - unfortunate because already in the first 1000 records
|
|
self._autocomplete('REF1230', 1, False)
|
|
# => Find exact match through the fallback
|
|
self._autocomplete('REF2230', 1, False)
|
|
|
|
# There are less than 1000 "N*" records
|
|
# => Fuzzy within N* (distance=1: add 1)
|
|
self._autocomplete('NUM000', 1, "num1000")
|
|
# => Exact match (distance=0 shortcut logic)
|
|
self._autocomplete('NUM100', 10, False)
|
|
# => Exact match (distance=0 shortcut logic)
|
|
self._autocomplete('NUM199', 9, False)
|
|
# => Exact match (distance=0 shortcut logic)
|
|
self._autocomplete('NUM1998', 1, False)
|
|
# => Fuzzy within N* (distance=1: replace 1 by 9)
|
|
self._autocomplete('NUM1999', 1, 'num1199')
|
|
# => Fuzzy within N* (distance=1: add 1)
|
|
self._autocomplete('NUM200', 1, 'num1200')
|
|
|
|
# There are no "X*" records
|
|
self._autocomplete('XEF1000', 0, "Not found")
|