Commit c61b0379 authored by Kazuhiko Shiozaki's avatar Kazuhiko Shiozaki

full text: add BooleanFullTextKey, that does 'AND' search by default.

parent b7c72455
<key_list>
<key>SearchableText</key>
<key>catalog_full_text.description</key>
<key>catalog_full_text.title</key> |
<key>description</key> |
<key>full_text.SearchableText</key> |
<key>title</key> |
</key_list>
\ No newline at end of file
<key_list>
<key>SearchableText | FullTextKey</key>
<key>catalog_full_text.description | FullTextKey</key>
<key>catalog_full_text.title | BooleanFullTextKey</key>
<key>description | FullTextKey</key>
<key>full_text.SearchableText | FullTextKey</key>
<key>title | BooleanFullTextKey</key>
</key_list>
\ No newline at end of file
SearchableText
catalog_full_text.description
catalog_full_text.title
description
full_text.SearchableText
title
\ No newline at end of file
SearchableText | FullTextKey
catalog_full_text.description | FullTextKey
catalog_full_text.title | BooleanFullTextKey
description | FullTextKey
full_text.SearchableText | FullTextKey
title | BooleanFullTextKey
\ No newline at end of file
...@@ -96,12 +96,31 @@ class MultivaluedComparisonOperator(ComparisonOperatorBase): ...@@ -96,12 +96,31 @@ class MultivaluedComparisonOperator(ComparisonOperatorBase):
verifyClass(IOperator, MultivaluedComparisonOperator) verifyClass(IOperator, MultivaluedComparisonOperator)
fulltext_boolean_detector = re.compile(r'((^|\s)[\+\-<>\(\~]|[\*\)](\s|$))')
class MatchComparisonOperator(MonovaluedComparisonOperator): class MatchComparisonOperator(MonovaluedComparisonOperator):
def __init__(self, operator, mode=''): def __init__(self, operator, mode=''):
MonovaluedComparisonOperator.__init__(self, operator, '') MonovaluedComparisonOperator.__init__(self, operator, '')
self.mode = mode self.mode = mode
self.where_expression_format_string = 'MATCH (%(column)s) AGAINST (%(value_list)s%(mode)s)' self.where_expression_format_string = 'MATCH (%(column)s) AGAINST (%(value_list)s%(mode)s)'
def renderValue(self, value_list):
"""
Special Query renderer for MroongaFullText queries:
* in boolean mode, we make 'AND' search by using '+word' format,
if no explicit boolean operation usage exists.
"""
if isinstance(value_list, list_type_list):
try:
value_list, = value_list
except ValueError:
raise ValueError, '%r: value_list must not contain more than one item. Got %r' % (self, value_list)
if self.mode == ' IN BOOLEAN MODE' and \
not fulltext_boolean_detector.search(value_list):
value_list = ' '.join(['+%s' % x for x in value_list.split()])
return self._renderValue(value_list)
def asSQLExpression(self, column, value_list, only_group_columns): def asSQLExpression(self, column, value_list, only_group_columns):
""" """
This operator can emit a select expression, so it overrides This operator can emit a select expression, so it overrides
......
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2014 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from FullTextKey import FullTextKey
from Products.ZSQLCatalog.interfaces.search_key import ISearchKey
from zope.interface.verify import verifyClass
class BooleanFullTextKey(FullTextKey):
"""
This SearchKey generates SQL fulltext comparisons for whose
default comparison operator is match_boolean.
"""
default_comparison_operator = 'match_boolean'
verifyClass(ISearchKey, BooleanFullTextKey)
...@@ -98,14 +98,15 @@ class FullTextKey(DefaultKey): ...@@ -98,14 +98,15 @@ class FullTextKey(DefaultKey):
value_list = operator_value_dict.pop(comparison_operator, []) value_list = operator_value_dict.pop(comparison_operator, [])
if not value_list: if not value_list:
continue continue
if logical_operator == 'or': # In MySQL FTS, no operator implies OR, but we make 'default
# AND' for boolean mode.
if (comparison_operator == 'match' and logical_operator == 'or') or \
(comparison_operator == 'match_boolean' and logical_operator == 'and'):
joined_value = ' '.join(value_list) joined_value = ' '.join(value_list)
append(SimpleQuery(search_key=self, append(SimpleQuery(search_key=self,
comparison_operator=comparison_operator, comparison_operator=comparison_operator,
group=group, **{column:joined_value})) group=group, **{column:joined_value}))
else: else:
# In MySQL FTS, no operator implies OR so that we cannot merge
# AND queries into one.
for value in value_list: for value in value_list:
append(SimpleQuery(search_key=self, append(SimpleQuery(search_key=self,
comparison_operator=comparison_operator, comparison_operator=comparison_operator,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment