經過兩個月的時間,畢設終於算是把所有主要功能都完成了,最近這一周為了實現全文檢索的功能,也算是查閱了不少資料,今天就在這里記錄一下,以免以后再用到時抓瞎了~
首先介紹一下我使用的Django全文檢索邏輯了,在網上查看了各種資料發現,Django上一般用到的檢索引擎基本上就是whoosh,sphinx,xapian了。后面的sphinx,xapian大家都可以在百度百科上找到相應的詞條,基本都是使用了很大的項目使用的,畢竟是基於C寫的,效率上肯定不必多言了,但是我這個殺雞的活還用不到這兩把牛刀了,這次我使用的是第一個whoosh引擎了,為什么使用這個呢?
因為whoosh是一個純python實現的全文搜索組件。
主要特性
- 敏捷的API(Pythonic API)。
- 純python實現,無二進制包。程序不會莫名其妙的崩潰。
- 按字段進行索引。
- 索引和搜索都非常的快 -- 是目前最快的純python全文搜索引擎。
- 良好的構架,評分模塊/分詞模塊/存儲模塊等各個模塊都是可插拔的。
- 功能強大的查詢語言(通過pyparsing實現功能)。
- 純python實現的拼寫檢查(目前唯一的純python拼寫檢查實現)
其實對我來說最重要的還是源於它的易用性和簡單,畢竟對於畢業設計來說,需要的時間復雜度還是很重要的"ㄟ( ▔, ▔ )ㄏ"
那么接下來就是分詞了~如果把用戶輸入的內容全部拿去檢索那不就和數據庫的模糊查詢一個意思了嘛~所以我需要一個能分詞的工具,但是whoosh的內部是使用正則來分詞的,雖然這在英文的世界里理所應當,但是畢竟我主要是用來檢索中文的,所以必須要有一個靠得住的中文分詞庫,而中文分詞要達到智能、准確並不是一件容易的事,目前國內有不少商業的分詞庫。當然了,也有一些免費的中文分詞庫可以使用,比如我使用的這個“jieba”分詞庫,而且他們號稱是“做最好的 Python 中文分詞組件”,這是他們的GitHub地址。
好了,現在檢索引擎和分詞庫都有了,那么接下來就是如何將這兩個整合到我們的項目中了~下面出場的就是今天的主角了~django-haystack,這個一款同時支持whoosh,solr,Xapian,Elasticsearc四種全文檢索引擎的第三方app,這意味着如果你不想使用whoosh,那你隨時可以將之更換成Xapian等其他搜索引擎,而不用更改代碼。正如Django一樣,Django-haystack的使用也非常簡單。
現在我們該把他們整合到一起了,首先,先把他們都安裝上吧
pip install whoosh
pip install jieba
pip install django-haystack
然后我們在app目錄下建立一個search_indexes.py,代碼如下:
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2015-05-07 14:15:13 # @Author : jonnyF (fuhuixiang@jonnyf.com) # @Link : http://jonnyf.com from dlnubuy.models import Product from haystack import indexes class ProductIndex(indexes.SearchIndex, indexes.Indexable): text = indexes.CharField(document=True, use_template=True) # 對pdname和description字段進行索引 pdname = indexes.CharField(model_attr='pdname') description = indexes.CharField(model_attr='description') def get_model(self): return Product def index_queryset(self, using=None): return self.get_model().objects.all()
這里要注意的是文件名稱必須是search_indexes.py,否則會報錯的!!!
然后在模板目錄下面建立templates/search/indexes/<appname>/product_text.txt,這個模板的作用是讓text字段包含的內容,在后面的模板中可能會有用。
然后在settings.py里面配置:
# full text search HAYSTACK_CONNECTIONS = { 'default': { 'ENGINE': 'dlnubuy.whoosh_cn_backend.WhooshEngine', 'PATH': os.path.join(BASE_DIR, 'whoosh_index'), }, }
# 自動更新索引 HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
這樣我們的檢索引擎,分詞器都連在一起了,但是要主要的一點是,我們現在的檢索引擎依舊使用的是自身的分詞器,而不是我們的jieba,所以接下來就是把他倆和在一起了,要注意的是我這里以及對whoosh的檢索引擎修改過了,所以為了方便移植,所以我將whoosh的檢索引擎放在了我app的目錄下面,這樣就不再依賴本機的環境了。
首先先將../Python27/Lib/site-packages/haystack/backends目錄中的whoosh_backend.py文件復制到app目錄下並改名為whoosh_cn_backend.py,這個文件名要和setting文件中配置中的一樣,當然,我們不是全部都修改這個文件,修改的僅僅是期中的個別位置,修改的地方如下:
#在全局引入的最后一行加入jieba分詞器 from jieba.analyse import ChineseAnalyzer #修改 schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=ChineseAnalyzer(), field_boost=field_class.boost, sortable=True)
之后是重建索引:python manage.py rebuild_index
這樣修改完成之后就可以使用了,關於自動更新索引這件事來說,我覺得並沒有必要在每次修改數據庫的時候都更新,所以后來改為了只有修改我檢索的字段的時候才使用manage.py update_index 更新索引。
接下來就是在搜索框提交之后來處理的后台邏輯了:
# 全局搜索 def full_search(request): sform = SearchForm(request.GET) posts = sform.search() template = 'product_search_list.html' c = Context({'posts': posts}) return render_to_response(template, c)
由於我使用的是模板來渲染的顯示頁面,所以在這個我就不貼出代碼來了(太簡單了,沒什么要注意的),主要就是在模板中使用循環來遍歷posts變量,而這個變量的類型是SearchResult的,這里就簡單的列舉一下SearchResult的一些參數了:
Attribute Reference The class exposes the following useful attributes/properties: app_label - The application the model is attached to. model_name - The model’s name. pk - The primary key of the model. score - The score provided by the search engine. object - The actual model instance (lazy loaded). model - The model class. verbose_name - A prettier version of the model’s class name for display. verbose_name_plural - A prettier version of the model’s plural class name for display. searchindex - Returns the SearchIndex class associated with this result. distance - On geo-spatial queries, this returns a Distance object representing the distance the result was from the focused point.
這里我使用的是object,然后通過{{i.object.description}}這樣的模板來顯示細節的,其他的地方就是具體項目具體細節咯~
以上便是我實現全文檢索的全部流程和邏輯,需要注意的是haystack的1.X版本和2.X版本在自動更新處還是有很大不同的,有些資料參考的時候還是要注意一下的(更新細節),今天在這里記錄下來,以免遺忘。by-JonnyF