You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bloodhound.apache.org by an...@apache.org on 2013/02/20 18:14:49 UTC

svn commit: r1448304 - in /incubator/bloodhound/trunk/bloodhound_search/bhsearch: ./ search_resources/ tests/ tests/search_resources/

Author: andrej
Date: Wed Feb 20 17:14:48 2013
New Revision: 1448304

URL: http://svn.apache.org/r1448304
Log:
#403 - Milestone renaming should be reflected in Bloodhound Search results

Modified:
    incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py
    incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py
    incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py
    incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/base.py
    incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/base.py
    incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/milestone_search.py
    incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/ticket_search.py
    incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py
    incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py
    incubator/bloodhound/trunk/bloodhound_search/bhsearch/whoosh_backend.py

Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py?rev=1448304&r1=1448303&r2=1448304&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/api.py Wed Feb 20 17:14:48 2013
@@ -87,12 +87,12 @@ class ISearchBackend(Interface):
     """
 
 #    def add_doc(self, doc, **kwargs):
-    def add_doc(doc, **kwargs):
+    def add_doc(doc, operation_context):
         """
         Called when new document instance must be added
         """
 
-    def delete_doc(doc_type, doc_id, **kwargs):
+    def delete_doc(doc_type, doc_id, operation_context):
         """
         Delete document from index
         """
@@ -102,16 +102,6 @@ class ISearchBackend(Interface):
         Optimize index if needed
         """
 
-    def commit(optimize, **kwargs):
-        """
-        Commit changes
-        """
-
-    def cancel(**kwargs):
-        """
-        Cancel changes if possible
-        """
-
     def recreate_index():
         """
         Create a new index, if index exists, it will be deleted
@@ -287,59 +277,53 @@ class BloodhoundSearchApi(Component):
         query_result.debug["api_parameters"] = query_parameters
         return query_result
 
+    def start_operation(self):
+        return self.backend.start_operation()
 
     def rebuild_index(self):
         """Rebuild underlying index"""
         self.log.info('Rebuilding the search index.')
         self.backend.recreate_index()
-        operation_data = self.backend.start_operation()
-        doc = None
-        try:
-            for participant in self.index_participants:
-                docs = participant.get_entries_for_index()
-                for doc in docs:
-#                    if doc["id"] == u'TracFastCgi':
-                    self._add_doc(doc, **operation_data)
+        with self.backend.start_operation() as operation_context:
             doc = None
-            self.backend.commit(True, **operation_data)
-        except Exception, ex:
-            self.log.error(ex)
-            if doc:
-                self.log.error("Doc that triggers the error: %s" % doc)
-            self.backend.cancel(**operation_data)
-            raise
-
-    def change_doc_id(self, doc, old_id):
-        operation_data = self.backend.start_operation()
-        try:
-            self.backend.delete_doc(
-                doc[IndexFields.TYPE],
-                old_id,
-                **operation_data)
-            self._add_doc(doc, **operation_data)
-            self.backend.commit(False, **operation_data)
-        except:
-            self.backend.cancel(**operation_data)
-            raise
+            try:
+                for participant in self.index_participants:
+                    docs = participant.get_entries_for_index()
+                    for doc in docs:
+                        self.add_doc(doc, operation_context)
+            except Exception, ex:
+                self.log.error(ex)
+                if doc:
+                    self.log.error("Doc that triggers the error: %s" % doc)
+                raise
+
+    def change_doc_id(self, doc, old_id, operation_context=None):
+        if operation_context is None:
+            with self.backend.start_operation() as operation_context:
+                self._change_doc_id(doc, old_id, operation_context)
+        else:
+            self._change_doc_id(doc, old_id, operation_context)
+
+    def _change_doc_id(self, doc, old_id, operation_context):
+        self.backend.delete_doc(
+            doc[IndexFields.TYPE],
+            old_id,
+            operation_context
+        )
+        self.add_doc(doc, operation_context)
 
 
     def optimize(self):
         """Optimize underlying index"""
         self.backend.optimize()
 
-    def add_doc(self, doc):
+    def add_doc(self, doc, operation_context = None):
         """Add a document to underlying search backend.
-
         The doc must be dictionary with obligatory "type" field
         """
-
-        operation_data = self.backend.start_operation()
-        try:
-            self._add_doc(doc, **operation_data)
-            self.backend.commit(False, **operation_data)
-        except:
-            self.backend.cancel(**operation_data)
-            raise
+        for preprocessor in self.index_pre_processors:
+            preprocessor.pre_process(doc)
+        self.backend.add_doc(doc, operation_context)
 
 
     def delete_doc(self, doc_type, doc_id):
@@ -347,18 +331,7 @@ class BloodhoundSearchApi(Component):
 
         The doc must be dictionary with obligatory "type" field
         """
-        operation_data = self.backend.start_operation()
-        try:
-            self.backend.delete_doc(doc_type, doc_id, **operation_data)
-            self.backend.commit(False, **operation_data)
-        except:
-            self.backend.cancel(**operation_data)
-            raise
+        self.backend.delete_doc(doc_type, doc_id)
 
 
-    def _add_doc(self, doc, **operation_data):
-        for preprocessor in self.index_pre_processors:
-            preprocessor.pre_process(doc)
-        self.backend.add_doc(doc, **operation_data)
-
 

Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py?rev=1448304&r1=1448303&r2=1448304&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py Wed Feb 20 17:14:48 2013
@@ -23,6 +23,7 @@ from bhsearch import BHSEARCH_CONFIG_SEC
 from bhsearch.api import (IIndexParticipant, BloodhoundSearchApi, IndexFields,
     ISearchParticipant)
 from bhsearch.search_resources.base import BaseIndexer, BaseSearchParticipant
+from bhsearch.search_resources.ticket_search import TicketIndexer
 from trac.ticket import IMilestoneChangeListener, Milestone
 from trac.config import ListOption, Option
 from trac.core import implements
@@ -64,11 +65,13 @@ class MilestoneIndexer(BaseIndexer):
                 raise
 
     def _rename_milestone(self, milestone, old_name):
-        #todo: reindex tickets that are referencing the renamed milestone
         try:
             doc = self.build_doc(milestone)
             search_api = BloodhoundSearchApi(self.env)
-            search_api.change_doc_id(doc, old_name)
+            with search_api.start_operation() as operation_context:
+                search_api.change_doc_id(doc, old_name, operation_context)
+                TicketIndexer(self.env).reindex_tickets(
+                    search_api, operation_context, milestone=milestone.name)
         except Exception, e:
             if self.silence_on_error:
                 self.log.error("Error occurs during renaming milestone from \

Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py?rev=1448304&r1=1448303&r2=1448304&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py Wed Feb 20 17:14:48 2013
@@ -81,14 +81,35 @@ class TicketIndexer(BaseIndexer):
             else:
                 raise
 
+    def reindex_tickets(self, search_api, operation_context, milestone=None):
+        for ticket in self._fetch_tickets(milestone):
+            self._index_ticket(ticket, search_api, operation_context)
+
+    def _fetch_tickets(self, milestone = None):
+#        with self.env.db_transaction as db:
+        for ticket_id in self._fetch_ids(milestone):
+            yield Ticket(self.env, ticket_id)
+
+    def _fetch_ids(self, milestone):
+        sql = "SELECT id FROM ticket"
+        args = []
+        conditions = []
+        if milestone:
+            args.append(milestone)
+            conditions.append("milestone=%s")
+        if conditions:
+            sql = sql + " WHERE " + " AND ".join(conditions)
+        for row in self.env.db_query(sql, args):
+            yield int(row[0])
+
+
     def _index_ticket(
-            self,
-            ticket,
-            ):
+            self, ticket, search_api = None, operation_context = None):
         try:
-            search_api = BloodhoundSearchApi(self.env)
+            if not search_api:
+                search_api = BloodhoundSearchApi(self.env)
             doc = self.build_doc(ticket)
-            search_api.add_doc(doc)
+            search_api.add_doc(doc, operation_context)
         except Exception, e:
             if self.silence_on_error:
                 self.log.error("Error occurs during ticket indexing. \
@@ -118,10 +139,7 @@ class TicketIndexer(BaseIndexer):
         return doc
 
     def get_entries_for_index(self):
-        #is there any better way to get all tickets?
-        query_records = self._load_ticket_ids()
-        for record in query_records:
-            ticket = Ticket(self.env, record["id"])
+        for ticket in self._fetch_tickets():
             yield self.build_doc(ticket)
 
     def _load_ticket_ids(self):

Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/base.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/base.py?rev=1448304&r1=1448303&r2=1448304&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/base.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/base.py Wed Feb 20 17:14:48 2013
@@ -38,7 +38,7 @@ class BaseBloodhoundSearchTest(unittest.
 
     def setUp(self, enabled = None, create_req = False):
         if not enabled:
-            enabled = ['bhsearch.*']
+            enabled = ['trac.*', 'bhsearch.*']
         self.env = EnvironmentStub(enable=enabled)
         self.env.path = tempfile.mkdtemp('bhsearch-tempenv')
         self.env.config.set('bhsearch', 'silence_on_error', "False")
@@ -75,7 +75,8 @@ class BaseBloodhoundSearchTest(unittest.
     def insert_ticket(self, summary, **kw):
         """Helper for inserting a ticket into the database"""
         ticket = self.create_ticket(summary, **kw)
-        return ticket.insert()
+        ticket.insert()
+        return ticket
 
     def create_wiki(self, name, text,  **kw):
         page = WikiPage(self.env, name)

Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/base.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/base.py?rev=1448304&r1=1448303&r2=1448304&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/base.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/base.py Wed Feb 20 17:14:48 2013
@@ -28,7 +28,6 @@ from trac.wiki import format_to_html
 class SimpleSearchWikiSyntaxFormatterTestCase(BaseBloodhoundSearchTest):
     def setUp(self):
         super(SimpleSearchWikiSyntaxFormatterTestCase, self).setUp(
-            ['trac.*', 'bhsearch.*'],
             create_req=True,
         )
         self.text_formatter = SimpleSearchWikiSyntaxFormatter(self.env)
@@ -57,7 +56,8 @@ class SimpleSearchWikiSyntaxFormatterTes
         self.assertEqual("sometext1 point1 sometext2", result)
 
     def test_can_format_wiki_link(self):
-        self.assertEqual("wiki:SomePage p1", self._call_format("[wiki:SomePage p1]"))
+        self.assertEqual(
+            "wiki:SomePage p1", self._call_format("[wiki:SomePage p1]"))
 
     def test_can_format_sample_wiki_link(self):
         self.assertEqual("WikiPage", self._call_format("WikiPage"))
@@ -83,17 +83,7 @@ class SimpleSearchWikiSyntaxFormatterTes
     def test_can_format_non_wiki_camel_case(self):
         self.assertEqual("WikiPage", self._call_format("!WikiPage"))
 
-
     def _call_format(self, wiki_content):
-#        page = self.create_wiki("Dummy wiki", wiki_content)
-#        from trac.mimeview.api import RenderingContext
-#        context = RenderingContext(
-#            page.resource,
-#            href=Href('/'),
-#            perm=MockPerm(),
-#        )
-#        context.req = None # 1.0 FIXME .req shouldn't be required by formatter
-#        result = self.text_formatter.format(context, wiki_content)
         result = self.text_formatter.format(wiki_content)
         print "Input text:"
         print wiki_content
@@ -118,7 +108,8 @@ class SimpleSearchWikiSyntaxFormatterTes
 
 def suite():
     test_suite = unittest.TestSuite()
-    test_suite.addTest(unittest.makeSuite(SimpleSearchWikiSyntaxFormatterTestCase, 'test'))
+    test_suite.addTest(
+        unittest.makeSuite(SimpleSearchWikiSyntaxFormatterTestCase, 'test'))
     return test_suite
 
 if __name__ == '__main__':

Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/milestone_search.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/milestone_search.py?rev=1448304&r1=1448303&r2=1448304&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/milestone_search.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/milestone_search.py Wed Feb 20 17:14:48 2013
@@ -121,6 +121,55 @@ class MilestoneIndexerEventsTestCase(Bas
         self.assertEqual(self.DUMMY_MILESTONE_NAME, doc["id"])
         self.assertEqual("milestone", doc["type"])
 
+    def test_that_tickets_updated_after_milestone_renaming(self):
+        #asser
+        INITIAL_MILESTONE = "initial_milestone"
+        RENAMED_MILESTONE = "renamed_name"
+        milestone = self.insert_milestone(INITIAL_MILESTONE)
+        self.insert_ticket("T1", milestone=INITIAL_MILESTONE)
+        self.insert_ticket("T2", milestone=INITIAL_MILESTONE)
+        #act
+        milestone.name = RENAMED_MILESTONE
+        milestone.update()
+        #assert
+        results = self.search_api.query("type:ticket")
+        self.print_result(results)
+        self.assertEqual(2, results.hits)
+        self.assertEqual(RENAMED_MILESTONE, results.docs[0]["milestone"])
+        self.assertEqual(RENAMED_MILESTONE, results.docs[1]["milestone"])
+
+    def test_that_tickets_updated_after_milestone_delete_no_retarget(self):
+        #asser
+        INITIAL_MILESTONE = "initial_milestone"
+        milestone = self.insert_milestone(INITIAL_MILESTONE)
+        self.insert_ticket("T1", milestone=INITIAL_MILESTONE)
+        self.insert_ticket("T2", milestone=INITIAL_MILESTONE)
+        #act
+        milestone.delete()
+        #assert
+        results = self.search_api.query("type:ticket")
+        self.print_result(results)
+        self.assertEqual(2, results.hits)
+        self.assertNotIn("milestone", results.docs[0])
+        self.assertNotIn("milestone", results.docs[1])
+
+    def test_that_tickets_updated_after_milestone_delete_with_retarget(self):
+        #asser
+        INITIAL_MILESTONE = "initial_milestone"
+        RETARGET_MILESTONE = "retarget_milestone"
+        milestone = self.insert_milestone(INITIAL_MILESTONE)
+        self.insert_milestone(RETARGET_MILESTONE)
+        self.insert_ticket("T1", milestone=INITIAL_MILESTONE)
+        self.insert_ticket("T2", milestone=INITIAL_MILESTONE)
+        #act
+        milestone.delete(retarget_to=RETARGET_MILESTONE)
+        #assert
+        results = self.search_api.query("type:ticket")
+        self.print_result(results)
+        self.assertEqual(2, results.hits)
+        self.assertEqual(RETARGET_MILESTONE, results.docs[0]["milestone"])
+        self.assertEqual(RETARGET_MILESTONE, results.docs[1]["milestone"])
+
 class MilestoneSearchParticipantTestCase(BaseBloodhoundSearchTest):
     def setUp(self):
         super(MilestoneSearchParticipantTestCase, self).setUp()

Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/ticket_search.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/ticket_search.py?rev=1448304&r1=1448303&r2=1448304&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/ticket_search.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/ticket_search.py Wed Feb 20 17:14:48 2013
@@ -53,22 +53,6 @@ class TicketIndexerTestCase(BaseBloodhou
         self.assertEqual(1, results.hits)
         self.assertEqual("Header", results.docs[0]["content"])
 
-    @unittest.skip("TODO")
-    def test_can_reflect_milestone_renaming(self):
-        #act
-        INITIAL_MILESTONE = "initial_milestone"
-        RENAMED_MILESTONE = "renamed_name"
-        milestone = self.insert_milestone(INITIAL_MILESTONE)
-        self.insert_ticket("T1", milestone=INITIAL_MILESTONE)
-        milestone.name = RENAMED_MILESTONE
-        milestone.update()
-
-        #assert
-        results = self.search_api.query("type:ticket")
-        self.print_result(results)
-        self.assertEqual(1, results.hits)
-        self.assertEqual(RENAMED_MILESTONE, results.docs[0]["milestone"])
-
 def suite():
     return unittest.makeSuite(TicketIndexerTestCase, 'test')
 

Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py?rev=1448304&r1=1448303&r2=1448304&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py Wed Feb 20 17:14:48 2013
@@ -27,7 +27,6 @@ from bhsearch.web_ui import RequestParam
 from bhsearch.whoosh_backend import WhooshBackend
 
 from trac.test import Mock, MockPerm
-from trac.ticket import Ticket
 from trac.core import TracError
 from trac.util.datefmt import FixedOffset
 from trac.util import format_datetime
@@ -40,7 +39,6 @@ DEFAULT_DOCS_PER_PAGE = 10
 class WebUiTestCaseWithWhoosh(BaseBloodhoundSearchTest):
     def setUp(self):
         super(WebUiTestCaseWithWhoosh, self).setUp(
-            ['trac.*', 'bhsearch.*'],
             create_req=True,
         )
         self.req.redirect = self.redirect
@@ -84,8 +82,7 @@ class WebUiTestCaseWithWhoosh(BaseBloodh
 
     def test_can_return_utc_time(self):
         #arrange
-        ticket_id = self.insert_ticket("bla")
-        ticket = Ticket(self.env, ticket_id)
+        ticket = self.insert_ticket("bla")
         ticket_time = ticket.time_changed
         #act
         self.req.args[RequestParameters.QUERY] = "*:*"
@@ -101,8 +98,7 @@ class WebUiTestCaseWithWhoosh(BaseBloodh
 
     def test_can_return_user_time(self):
         #arrange
-        ticket_id = self.insert_ticket("bla")
-        ticket = Ticket(self.env, ticket_id)
+        ticket = self.insert_ticket("bla")
         ticket_time = ticket.time_changed
         #act
         self.req.tz = FixedOffset(60, 'GMT +1:00')

Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py?rev=1448304&r1=1448303&r2=1448304&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py Wed Feb 20 17:14:48 2013
@@ -451,6 +451,41 @@ class WhooshFunctionalityTestCase(unitte
             facets_result[name] = non_paged_results.groups(name)
         return facets_result
 
+    def test_can_auto_commit(self):
+        # pylint: disable=unused-argument
+
+        schema = Schema(
+                unique_id=ID(stored=True, unique=True),
+                type=ID(stored=True),
+                )
+
+        ix = index.create_in(self.index_dir, schema=schema)
+        with ix.writer() as w:
+            w.add_document(unique_id=u"1", type=u"type1")
+            w.add_document(unique_id=u"2", type=u"type2")
+
+        with ix.searcher() as s:
+            results = s.search(query.Every())
+            self.assertEquals(2, len(results))
+
+    def test_can_auto_cancel(self):
+        schema = Schema(
+                unique_id=ID(stored=True, unique=True),
+                type=ID(stored=True),
+                )
+
+        ix = index.create_in(self.index_dir, schema=schema)
+        try:
+            with ix.writer() as w:
+                w.add_document(unique_id=u"1", type=u"type1")
+                w.add_document(unique_id=u"2", type=u"type2")
+                raise Exception("some exception")
+        except Exception:
+            pass
+
+        with ix.searcher() as s:
+            results = s.search(query.Every())
+            self.assertEquals(0, len(results))
 
 class WhooshEmptyFacetErrorWorkaroundTestCase(BaseBloodhoundSearchTest):
     def setUp(self):

Modified: incubator/bloodhound/trunk/bloodhound_search/bhsearch/whoosh_backend.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/bloodhound_search/bhsearch/whoosh_backend.py?rev=1448304&r1=1448303&r2=1448304&view=diff
==============================================================================
--- incubator/bloodhound/trunk/bloodhound_search/bhsearch/whoosh_backend.py (original)
+++ incubator/bloodhound/trunk/bloodhound_search/bhsearch/whoosh_backend.py Wed Feb 20 17:14:48 2013
@@ -76,17 +76,18 @@ class WhooshBackend(Component):
 
     #ISearchBackend methods
     def start_operation(self):
-        return dict(writer = self._create_writer())
+        return self._create_writer()
 
     def _create_writer(self):
         return AsyncWriter(self.index)
 
-    def add_doc(self, doc, writer=None):
+    def add_doc(self, doc, operation_context=None):
         """Add any type of  document index.
 
         The contents should be a dict with fields matching the search schema.
         The only required fields are type and id, everything else is optional.
         """
+        writer = operation_context
         is_local_writer = False
         if writer is None:
             is_local_writer = True
@@ -118,9 +119,10 @@ class WhooshBackend(Component):
             else:
                 doc[key] = self._to_whoosh_format(value)
 
-    def delete_doc(self, doc_type, doc_id, writer=None):
+    def delete_doc(self, doc_type, doc_id, operation_context=None):
         unique_id = self._create_unique_id(doc_type, doc_id)
         self.log.debug('Removing document from the index: %s', unique_id)
+        writer = operation_context
         is_local_writer = False
         if writer is None:
             is_local_writer = True
@@ -139,15 +141,6 @@ class WhooshBackend(Component):
         writer = AsyncWriter(self.index)
         writer.commit(optimize=True)
 
-    def commit(self, optimize, writer):
-        writer.commit(optimize=optimize)
-
-    def cancel(self, writer):
-        try:
-            writer.cancel()
-        except Exception, ex:
-            self.env.log.error("Error during writer cancellation: %s", ex)
-
     def recreate_index(self):
         self.log.info('Creating Whoosh index in %s' % self.index_dir)
         self._make_dir_if_not_exists()
@@ -380,7 +373,12 @@ class WhooshEmptyFacetErrorWorkaround(Co
                     if field == self.NULL_MARKER:
                         count_dict[None] = count
                         del count_dict[self.NULL_MARKER]
-        #we can fix query_result.docs later if needed
+
+        #fix query_result.docs
+        for doc in query_result.docs:
+            for field, value in doc.items():
+                if value == self.NULL_MARKER:
+                    del doc[field]
 
     #IQueryPreprocessor methods
     def query_pre_process(self, query_parameters):