接着上篇文章我们继续往下走,在这里我们来跟踪源码,看看edx是如何利用elasticsearch来搜索课程/内容的

首先在上篇文章里,我们知道了:在lms中搜索课程时,其实是发出ajax请求,而后search服务响应这个请求,前台将其呈现给用户。这种设计在edx中随处可见,通过RESTful风格的接口,来将功能模块化。如此一来职责清晰,耦合度里,模块化高

#定义目标 我们此次探索源码的目标是了解搜索相关的逻辑代码,看看适合在哪里开始定制。以及找到edx利用elasticsearch的机制,在那里我们可以将搜索问题变成elasticsearch的问题,借助elasticsearch,我们能获得惊人的搜索能力,elasticsearch有许多强大的插件,诸如中文分词插件,这对中文搜索很重要,对搜索的大动干戈建议从elasticsearch入手。

#Go 我喜欢通过github读代码,有种破案推理的乐趣。当然啦更现代化的方法是使用Source Insight之类的工具或是使用打断点堆栈跟踪之类的方法

我喜欢github是因为这种泛泛的搜索,常常有意外的收获,牺牲针精确换取更宽的视野。

时有物外之趣

下边开始我们的旅程。

从上篇文章我们知道数据的来源是这几个url:

  • /search/
  • /search/<COURSE_ID>
  • /search/course_discovery

我们以此为切入点,首先定位到

url(r'^search/', include('search.urls')),

这个url会把我们引入edx-search

通过url.py我们顺利找到入口

1
2
3
    url(r'^$', views.do_search, name='do_search'),
    url(r'^{}$'.format(COURSE_ID_PATTERN), views.do_search, name='do_search'),
    url(r'^course_discovery/$', views.course_discovery, name='course_discovery'),

顺藤摸瓜找到相关的view

###跟踪内容搜素(do_search) 我对搜索课程内容更感兴趣,所以先跟踪do_search

此外我们有个意外的发现,搜索会触发track.emit,这意味着搜索这个事件会被记录,之后在insights中可能会有显示

不难发现results是搜索所得的核心的数据,顺藤摸瓜,追踪到.api模块里的perform_search函数

=> searcher

=> SearchEngine

我们看到这是一个抽象类,许多方法有待实现

=> get_search_engine

=> search_engine_class

SEARCH_ENGINE在Enabling Open edX Search里有提到,生产环境用的是search.elastic.ElasticSearchEngine

=> ElasticSearchEngine

我们如愿以偿地找到了search

顺便我们还发现了index

又经过了层层包装,都在ElasticSearchEngine类里了(主要在search里),把搜索参数最终传递给elasticsearch:

1
2
3
4
5
            es_response = self._es.search(
                index=self.index_name,
                body=body,
                **kwargs
            )

我们顺便跟踪一下_es

=> self._es = getattr(settings, “ELASTIC_SEARCH_IMPL”, Elasticsearch)(es_config)

=> from elasticsearch import Elasticsearch

最后我们回到elasticsearch-pysearch方法,这样我们就把整个流程走完了

至于elasticsearch-py如何封装elasticsearch,我觉得暂时可以不用关心

中间的这个流程,任何一个环节我们都可能进行定制修改。

enjoy it