(wip) udpate elasticsearch indexes after modifying parent relation (related #13967211)

authorKatia Saurfelt <katia.saurfelt@logilab.fr>
changesetc5915fe34673
branchdefault
phasedraft
hiddenyes
parent revision#9fca73587475 [pkg] use beautifulsoup4 instead of bs4
child revision<not specified>
files modified by this revision
hooks.py
test/test_parents.py
# HG changeset patch
# User Katia Saurfelt <katia.saurfelt@logilab.fr>
# Date 1485359871 -3600
# Wed Jan 25 16:57:51 2017 +0100
# Node ID c5915fe34673b498b0f81a8afd0ffefab34b8550
# Parent 9fca73587475373e91dc7f5ecd8142c3b3246573
(wip) udpate elasticsearch indexes after modifying parent relation (related #13967211)

diff --git a/hooks.py b/hooks.py
@@ -47,17 +47,37 @@
1          if self.entity.cw_etype == 'File':
2              return  # FIXME hack!
3          IndexEsOperation.get_instance(self._cw).add_data(self.entity)
4 
5 
6 +class RelationsUpdateIndexES(hook.Hook):
7 +
8 +    """detect relations changes and updates ES indexing"""
9 +
10 +    __regid__ = 'elasticsearch.relationsupdatetoes'
11 +    events = ('after_add_relation', 'before_delete_relation')
12 +    category = 'es'
13 +
14 +    def __call__(self):
15 +        # XXX add a selector for object and subject
16 +        for entity in (self._cw.entity_from_eid(self.eidfrom),
17 +                       self._cw.entity_from_eid(self.eidto)):
18 +            cw_etype = entity.cw_etype
19 +            if cw_etype == 'File':
20 +                return  # FIXME hack!
21 +            if (cw_etype in indexable_types(entity._cw.vreg.schema) or
22 +                    cw_etype in CUSTOM_ATTRIBUTES):
23 +                IndexEsOperation.get_instance(self._cw).add_data(entity)
24 +
25 +
26  class IndexEsOperation(hook.DataOperationMixIn, hook.Operation):
27 
28      def precommit_event(self):
29          indexer = self.cnx.vreg['es'].select('indexer', self.cnx)
30          es = indexer.get_connection()
31          if es is None:
32 -            log.info('no connection to ES (not configured) skip ES indexing')
33 +            log.error('no connection to ES (not configured) skip ES indexing')
34              return
35          for entity in self.get_data():
36              rql = fulltext_indexable_rql(entity.cw_etype,
37                                           entity._cw.vreg.schema,
38                                           eid=entity.eid)
diff --git a/test/test_parents.py b/test/test_parents.py
@@ -30,21 +30,21 @@
39  class ParentsSearchTC(testlib.CubicWebTC):
40 
41      @classmethod
42      def setUpClass(cls):
43          try:
44 -            httplib.HTTPConnection('localhost:9200').request('GET', '/')
45 +            httplib.HTTPConnection('172.17.1.77:9200').request('GET', '/')
46          except:
47              raise unittest.SkipTest('No ElasticSearch on localhost, skipping test')
48          super(ParentsSearchTC, cls).setUpClass()
49 
50      def setup_database(self):
51          super(ParentsSearchTC, self).setup_database()
52          self.orig_config_for = CubicWebConfiguration.config_for
53          config_for = lambda appid: self.config  # noqa
54          CubicWebConfiguration.config_for = staticmethod(config_for)
55 -        self.config['elasticsearch-locations'] = 'http://localhost:9200'
56 +        self.config['elasticsearch-locations'] = 'http://172.17.1.77:9200'
57          # TODO unique ID to avoid collision
58          self.config['index-name'] = 'unittest_index_name'
59          # remove default connection if there's one
60          try:
61              connections.remove_connection('default')
@@ -87,10 +87,36 @@
62                                          fuzzy=True)
63                  self.assertEquals(len(search.execute()), number_of_results)
64                  self.assertEquals(search.execute().to_dict()['hits']['hits'][0]['_source']['title'],
65                                    first_result)
66 
67 +    def test_es_hooks_modify_relation(self):
68 +        with self.admin_access.cnx() as cnx:
69 +            with self.temporary_appobjects(BlogFTIAdapter):
70 +                indexer = cnx.vreg['es'].select('indexer', cnx)
71 +                indexer.get_connection()
72 +                indexer.create_index(custom_settings={
73 +                    'mappings': {
74 +                        'BlogEntry': {'_parent': {"type": "Blog"}},
75 +                    }
76 +                })
77 +                blog1 = cnx.create_entity('Blog', title=u'Blog')
78 +                entity = cnx.create_entity('BlogEntry',
79 +                                           title=u'Article about stuff',
80 +                                           content=u'content herer',
81 +                                           entry_of=blog1)
82 +                blog2 = cnx.create_entity('Blog', title=u'Blog')
83 +                cnx.commit()
84 +                time.sleep(2)  # TODO find a way to have synchronous operations in unittests
85 +
86 +                blog2.cw_set(reverse_entry_of=entity)
87 +                cnx.commit()
88 +                search = Search(index=self.config['index-name'],
89 +                                doc_type='Blog').query(
90 +                                    "match", eid=entity.eid)
91 +                print(search.execute().to_dict()['hits']['hits'])
92 +
93      def tearDown(self):
94          with self.admin_access.cnx() as cnx:
95              indexer = cnx.vreg['es'].select('indexer', cnx)
96              es = indexer.get_connection()
97              es.indices.delete(self.config['index-name'])