博主信息
小猿猿er
博文
13
粉絲
1
評論
1
訪問量
4793
積分:0
P豆:30.5

新疆十一选五前三组选:使用sphinx search打造你自己的中文搜索引擎

2019年05月07日 10:54:27閱讀數:414博客 / 小猿猿er / Python教程

新疆十一选五预测号码今天 www.envkt.com 為了有一個更好的閱讀體驗請移步至我的技術博客:猿人學

Google搜索引擎建立至今已經快20年了,之后全球各類大大小小類似的搜索引擎也陸續出現、消亡。國內目前以百度為大,搜狗、360、必應等也勢在必爭。搜索引擎技術也發展的相當成熟,同時也就出現了很多開源的搜索引擎系統。比如,Solr、Lucene、Elasticsearch、Sphinx等。

本文以sphinx search為例來介紹如何打造自己的搜索引擎。該搜索引擎的架構大致如下:

Sphinx search

Sphinx search 是俄羅斯人用C++寫的,速度很快,可以非常容易的與SQL數據庫和腳本語言集成,內置MySQL和PostgreSQL 數據庫數據源的支持。其官方網站是: //sphinxsearch.com/

可以說Sphinx支持包括英文、中文等所有語言的搜索。英文是以空格、標點符號來分割單詞的,很容易切分。而中文詞匯之間是沒有空格的,很難區分,所以才有了自然語言處理中的“中文分詞”技術的研究。Sphinx默認把中文按字拆分的,但這樣就會產生搜索出不相干的內容來。比如,搜索“中國”,它會把同時包含“中”和“國”但不包含“中國”的文檔搜出來。因此,有人就給Sphinx打了中文分詞的補丁。

如果沒有搞錯的話,最早添加中文分詞的是Coreseek,好像也是中文圈用得最廣的支持中文分詞的Sphinx,其它還有sphinx-for-chinese。然而這二者基于的Sphinx版本都太低了,有好多年沒有更新。其中存在的一些Sphinx的bug也沒有解決。

github上有一個基于Sphinx 2.2.9版本的代碼庫添加了中文分詞: https://github.com/eric1688/sphinx  經測試,該版本穩定性和速度都要好于coreseek。當然它依然支持英文等其它語言的搜索,只是對中文搜索更加準確了。

Sphinx 安裝

git clone https://github.com/eric1688/sphinx
cd sphinx#編譯(假設安裝到/usr/local/sphinx目錄,下文同) ./configure --prefix=/usr/local/sphinx# 說明: --prefix 指定安裝路徑 --with-mysql 編譯mysql支持 --with-pgsql 編譯pgsql支持make
sudo make install

安裝好后,在/usr/local/sphinx目錄下有以下幾個子目錄:
etc/  sphinx配置文件,不同的索引可以寫不同的配置文件
bin/  sphinx程序,其中有建立索引的程序:indexer, 搜索守護進程:searchd
var/  一般用了放置indexer索引好的文件

Sphinx索引的建立

MySQL數據庫表結構 
從上面的架構圖可以看出來,我們要搜索的數據都存放在MySQL數據庫中。假設我們的數據庫名稱叫blog_data,其中有個表叫article,表結構如下:

字段名

說明

id    文章唯一id(主鍵)    

title    文章標題    

content    文章內容    

created_time    文章創建時間    

該article表可以是你本身網站的文本內容存放的表格,也可以是你的網絡爬蟲抓取到的數據存儲表。

還有建立另外一個表sph_counter用來存儲indexer已經索引的最大doc id

字段名

說明

counter_id    標記是對哪個表做記錄    

max_doc_id    被索引表的最大ID    

note    注釋,可以是表名    

update_at    更新時間    

建立索引配置文件:  
新建或修改/usr/local/sphinx/etc/blog.conf 配置文件:

source blog_main
{
   type          = mysql
   sql_host      = localhost
   sql_user      = reader
   sql_pass      = readerpassword
   sql_db        = blog_data
   sql_port      = 3306
   sql_query_pre = SET NAMES utf8mb4
   sql_query_pre = REPLACE INTO sph_counter SELECT 1, MAX(id), 'article', NOW() FROM article

   sql_query     = SELECT id, title, content,  \
                   UNIX_TIMESTAMP(created_time) AS ctime, \
                   FROM article \
                   WHERE id <= (SELECT max_doc_id from sph_counter WHERE counter_id=1)
   sql_attr_timestamp = ctime  #從SQL讀取到的值必須為整數,作為時間屬性

}index blog_main{
   source       = blog_main #對應的source名稱
   path         = /user/local/sphinx/var/data/blog_main
   docinfo      = extern
   mlock        = 0
   morphology   = none
   min_word_len = 1
   html_strip   = 0

   charset_type     = utf-8
   chinese_dictionary = /user/local/sphinx/etc/xdict  #中文分詞的詞典
   ngram_len = 0
   stopwords        = /user/local/sphinx/etc/stop_words.utf8}

#全局index定義indexer{
   mem_limit = 512M}

#searchd服務定義searchd{
   listen          = 9900
   listen          = 9306:mysql41  # 實時索引監聽的端口
   read_timeout    = 5
   max_children    = 90
   max_matches     = 100000
   max_packet_size = 32M
   read_buffer     = 1M
   subtree_docs_cache = 8M
   subtree_hits_cache = 16M
   #workers        = threads?
   dist_threads    = 2
   seamless_rotate = 0
   preopen_indexes = 0
   unlink_old      = 1
   pid_file  = /usr/local/sphinx/var/log/blog_searchd_mysql.pid
   log       = /usr/local/sphinx/var/log/blog_searchd_mysql.log
   query_log = /usr/local/sphinx/var/log/blog_query_mysql.log}

編輯好以上配置文件,就可以開始建立索引了:

cd /usr/local/sphinx/bin
./indexer -c ../etc/blog.conf# 如果已經有searchd在運行了,就要加 --roate 來進行索引

索引建立后,就會在var/data/下面有名稱前綴為blog_main.XXX的索引文件生成。

建立實時索引 
上面的配置文件是建立一個靜態索引,把當時數據庫里面的所有數據進行索引。但是,你的數據庫往往是不斷增加新數據的。為了及時索引并搜索到最新加入的數據,就需要配置實時索引了。

index rt_weixin                                                                                                     {
   type = rt
   path = /usr/local/sphinx/var/data/rt_blog
   rt_field = title
   rt_field = content

   rt_attr_timestamp = pubtime
   ngram_chars = U+3000..U+2FA1F #為了支持中文
   ngram_len = 1}

該倉庫代碼的作者可能是忘了給實時索引加中文分詞,如果不配置ngram_chars 參數就不能搜到中文,添加后搜索是按單字匹配的,可見作者確實是忘了給實時索引部分加中文分詞。

添加以上實時索引后并不能搜索到實時數據。實時索引的更新/添加只能通過SphinxQL(一個類似MySQL的協議),所以還要寫一個Python腳本,從數據庫讀取最新的數據并通過SphinxQL更新到實時索引。

import MySQLdb# 連接實時索引db_rt = MySQLdb.connect(
   '127.0.0.1',
   'nodb',  # 對于實時索引來說,db,user,password都是不需要的,隨便寫。
   'noname',
   'nopass',
   port=9306,  # 實時索引監聽的端口)  # 向實時索引更新數據的函數def into_rt(index_name, item):
   cursor = db_rt.cursor()
   fields = item.keys()
   values = item.values()
   fieldstr = ','.join(fields)
   valstr = ','.join(["'%s'"] * len(item))
   for i in xrange(len(values)):
       if isinstance(values[i], unicode):
           values[i] = values[i].encode('utf8')
       elif isinstance(values[i], datetime):
           try:
               values[i] = int(time.mktime(values[i].timetuple()))
           except:
               traceback.print_exc()
               print values[i]
               values[i] = int(time.time())
   sql = 'INSERT INTO %s (%s) VALUES(%s)' % (index_name, fieldstr, valstr)
   # print sql
   sql = sql % tuple(values)
   try:
       cursor.execute(sql)
       db_rt.commit()
   except Exception, e:
       if e[0] == 1064:
           # ignore duplicated id error
           pass
       else:
           traceback.print_exc()
           raise 'realtime index error'
   finally:
       cursor.close()

以上是及時建立實時索引的python程序的主要部分??梢園閹柚貿珊筇ㄒ恢痹誦械氖鼗こ絳?,也可以在crontab里面配置每隔幾分鐘運行一次。

索引的更新 
靜態的主索引如果只建立一次,實時索引的數據量會越積越多,對實時索引的搜索帶來很大壓力,所以我們要定時重新建立主索引,清理實時索引。
清理實時索引的程序可以參考上面建立實時索引的python程序。

crontab 設置每天凌晨1點運行 indexer

crontab 設置indexer運行完畢后清理實時索引,并從新的max_doc_id開始建立實時索引

以上就是建立一個自己的搜索引擎的過程。更多配置細節可到官方網站參考文檔。


全部評論

文明上網理性發言,請遵守新聞評論服務協議

條評論
暫無評論暫無評論!