Django 2.1.7 全文檢索

  • 2019 年 10 月 6 日
  • 筆記

全文檢索

全文檢索不同於特定欄位的模糊查詢,使用全文檢索的效率更高,並且能夠對於中文進行分詞處理。

  • haystack:全文檢索的框架,支援whoosh、solr、Xapian、Elasticsearc四種全文檢索引擎,點擊查看官方網站
  • whoosh:純Python編寫的全文搜索引擎,雖然性能比不上sphinx、xapian、Elasticsearc等,但是無二進位包,程式不會莫名其妙的崩潰,對於小型的站點,whoosh已經足夠使用,點擊查看whoosh文檔
  • jieba:一款免費的中文分詞包,如果覺得不好用可以使用一些收費產品。

安裝配置示例

1)在虛擬環境中依次安裝需要的包。

pip3 install django-haystack  pip3 install whoosh  pip3 install jieba

2)修改項目的settings.py文件,安裝應用haystack。

INSTALLED_APPS = [      ...        # Added.      'haystack',    ]

3)在項目的settings.py文件中配置搜索引擎。

settings.py中,需要添加一個設置來指示項目的站點配置文件將存在的位置以及要使用的後端,以及該後端的其他設置。

因為這裡演示是使用whoosh,所以下面是關於whoosh作為後端的示例:

HAYSTACK_CONNECTIONS = {      'default': {          #使用whoosh引擎          'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',          #索引文件路徑          'PATH': os.path.join(BASE_DIR, 'whoosh_index'),      }  }    #當添加、修改、刪除數據時,自動生成索引  HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

其他後端更多配置參考官網文檔:http://docs.haystacksearch.org/en/master/tutorial.html

4)修改whoosh使用jieba中文分詞

上面的默認whoosh只能夠對英文單詞進行分詞,無法對中文語句進行分詞。 例如:將 我愛中國 拆分成 中國

jieba示例示例:

In [1]: import jieba    In [2]: str = '我愛中國'    In [4]: res = jieba.cut(str, cut_all=True)    In [5]: res  Out[5]: <generator object Tokenizer.cut at 0x00000195BBC61C00>    In [6]: for val in res:     ...:     print(val)     ...:  Building prefix dict from the default dictionary ...  Dumping model to file cache C:UsersADMINI~1AppDataLocalTempjieba.cache  Loading model cost 0.643 seconds.  Prefix dict has been built succesfully.  我  愛  中國    In [7]: 

下面來改寫whoosh的後端文件。

5)改寫whoosh的後端庫文件

  • 首先需要安裝號jieba的分詞庫

pip3 install jieba

  • 找到haystack的庫文件目錄

因為我這次安裝在虛擬環境中,所以需要到庫文件中尋找。

  • 打開haystack下的backends目錄

haystack/backends目錄下創建ChineseAnalyzer.py文件

import jieba  from whoosh.analysis import Tokenizer, Token    class ChineseTokenizer(Tokenizer):      def __call__(self, value, positions=False, chars=False,                   keeporiginal=False, removestops=True,                   start_pos=0, start_char=0, mode='', **kwargs):          t = Token(positions, chars, removestops=removestops, mode=mode, **kwargs)          seglist = jieba.cut(value, cut_all=True)          for w in seglist:              t.original = t.text = w              t.boost = 1.0              if positions:                  t.pos = start_pos + value.find(w)              if chars:                  t.startchar = start_char + value.find(w)                  t.endchar = start_char + value.find(w) + len(w)              yield t    def ChineseAnalyzer():      return ChineseTokenizer()
  • 複製whoosh_backend.py文件,改為如下名稱whoosh_cn_backend.py
  • 打開複製出來的新文件whoosh_cn_backend.py,引入中文分析類,內部採用jieba分詞。
from .ChineseAnalyzer import ChineseAnalyzer
  • 更改詞語分析類。
查找  analyzer=StemmingAnalyzer()  改為  analyzer=ChineseAnalyzer()
  • 修改settings.py文件中的配置項。
# 全文檢索框架的配置  HAYSTACK_CONNECTIONS = {      'default': {          # 使用whoosh引擎          # 'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',          'ENGINE': 'haystack.backends.whoosh_cn_backend.WhooshEngine',          # 索引文件路徑          'PATH': os.path.join(BASE_DIR, 'whoosh_index'),      }  }    # 當添加、修改、刪除數據時,自動生成索引  HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'    # 指定搜索結果每頁顯示的條數  HAYSTACK_SEARCH_RESULTS_PER_PAGE=1

好了,到這裡已經配置好了中文分詞的全文檢索。下面來看看怎麼使用。

  • 在項目/urls.py中添加搜索的配置。
path('search/', include('haystack.urls')), # 導入haystack應用的urls.py

創建引擎及索引

1)在應用目錄下創建search_indexes.py文件。

在search_indexes.py定義一個伺服器索引類。

from haystack import indexes  from assetinfo.models import ServerInfo # 伺服器資訊類    #指定對於某個類的某些數據建立索引  class ServerInfoIndex(indexes.SearchIndex, indexes.Indexable):      text = indexes.CharField(document=True, use_template=True)        def get_model(self):          return ServerInfo        def index_queryset(self, using=None):          return self.get_model().objects.all()

2)在templates目錄下創建"search/indexes/assetinfo/"目錄,在目錄中創建"serverinfo_text.txt"文件

  1. 在"serverinfo_text.txt"文件設置欄位索引

欄位索引格式如下:

#指定索引的屬性  {{object.gcontent}}

查看一下全文索引的模型類ServerInfo

可以看到,可以使用紅色框住的三個欄位作為索引。

# 指定根據表中的哪些欄位建立索引數據  {{ object.server_hostname }} # 根據伺服器的名稱建立索引  {{ object.server_intranet_ip }} # 根據伺服器的內網IP建立索引  {{ object.server_internet_ip }} # 根據伺服器的外網IP建立索引

4)初始化索引數據。

python3 manage.py rebuild_index

5)索引生成後目錄結構如下圖:

使用全文檢索

1)在assetinfo/views.py中定義視圖query。

def query(request):      return render(request,'assetinfo/query.html')

2)在assetinfo/urls.py中配置。

urlpatterns = [      # ex:/assetinfo/query      path('query', views.query , name='query'),  ]

3)在templates/assetinfo/目錄中創建模板query.html。

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">      <title>全文檢索</title>  </head>  <body>      <form method='get' action="/search/" target="_blank">          <input type="text" name="q">          <br>          <input type="submit" value="查詢">      </form>  </body>  </html>

4)自定義搜索結果模板:在templates/search/目錄下創建search.html。

搜索結果進行分頁,視圖向模板中傳遞的上下文如下:

  • query:搜索關鍵字
  • page:當前頁的page對象
  • paginator:分頁paginator對象

視圖接收的參數如下:

  • 參數q表示搜索內容,傳遞到模板中的數據為query
  • 參數page表示當前頁碼
<html>  <head>      <title>全文檢索--結果頁</title>  </head>  <body>  <h1>搜索&nbsp;<b>{{query}}</b>&nbsp;結果如下:</h1>  <ul>  {%for item in page%}      <li>{{item.object.id}}--{{item.object.gcontent|safe}}</li>      <li>{{item.object.id}}--{{item.object.server_hostname|safe}}</li>  {%empty%}      <li>啥也沒找到</li>  {%endfor%}  </ul>  <hr>  {%for pindex in page.paginator.page_range%}      {%if pindex == page.number%}          {{pindex}}&nbsp;&nbsp;      {%else%}          <a href="?q={{query}}&amp;page={{pindex}}">{{pindex}}</a>&nbsp;&nbsp;      {%endif%}  {%endfor%}  </body>  </html>

5)運行伺服器,在瀏覽器中輸入如下地址: http://127.0.0.1:8000/assetinfo/query

在文本框中填寫要搜索的資訊,點擊」搜索「按鈕。

搜索結果如下: