Scrapy分散式爬蟲打造搜尋引擎-(八)elasticsearch結合django搭建搜尋引擎

天涯明月笙發表於2017-07-01

Python分散式爬蟲打造搜尋引擎

基於Scrapy、Redis、elasticsearch和django打造一個完整的搜尋引擎網站

推薦前往我的個人部落格進行閱讀:http://blog.mtianyan.cn/
目錄分章效果更佳哦

分章檢視目錄:

  1. Scrapy分散式爬蟲打造搜尋引擎 – (一)基礎知識
  2. Scrapy分散式爬蟲打造搜尋引擎 – (二)伯樂線上爬取所有文章
  3. Scrapy分散式爬蟲打造搜尋引擎 – (三)知乎網問題和答案爬取
  4. Scrapy分散式爬蟲打造搜尋引擎 – (四)通過CrawlSpider對拉勾網進行整站爬取
  5. Scrapy分散式爬蟲打造搜尋引擎-(五)爬蟲與反爬蟲的戰爭
  6. Scrapy分散式爬蟲打造搜尋引擎-(六)scrapy進階開發
  7. Scrapy分散式爬蟲打造搜尋引擎-(七)scrapy-redis 分散式爬蟲
  8. Scrapy分散式爬蟲打造搜尋引擎-(八)elasticsearch結合django搭建搜尋引擎

八、elasticsearch搭建搜尋引擎

elasticsearch介紹:一個基於lucene的搜尋伺服器,分散式多使用者的全文搜尋引擎 java開發的 基於restful web介面
自己搭建的網站或者程式,新增搜尋功能比較困難
所以我們希望搜尋解決方案要高效
零配置並且免費
能夠簡單的通過json和http與搜尋引擎互動
希望搜尋服務很穩定
簡單的將一臺伺服器擴充套件到多臺伺服器

內部功能:
分詞 搜尋結果打分 解析搜尋要求
全文搜尋引擎:solr sphinx
很多大公司都用elasticsearch 戴爾 Facebook 微軟等等

  1. elasticsearch對Lucene進行了封裝,既能儲存資料,又能分析資料,適合與做搜尋引擎
    關係資料搜尋缺點:
    無法對搜素結果進行打分排序
    沒有分散式,搜尋麻煩,對程式設計師的要求比較高
    無法解析搜尋請求,對搜尋的內容無法進行解析,如分詞等
    資料多了,效率低
    需要分詞,把關係,資料,重點分出來

  2. nosql資料庫:
    文件資料庫 json程式碼,在關聯式資料庫中資料儲存,需要存到多個表,內部有多對多等關係之類的,需要涉及到多個表才能將json裡面的內容存下來,nosql直接將一個json的內容存起來,作為一個文件存檔到資料庫。
    mongodb:

1. elasticsearch安裝與配置

  1. java sdk安裝
  1. elasticsearch安裝官網下載 不使用官網的版本,提供原始的外掛不多
  2. elasticsearc-rtf github搜尋,中文發行版,已經安裝了很多外掛 https://github.com/medcl/elasticsearch-rtf
  3. 執行elasticsearch的方法,在bin檔案目錄下進入命令列,執行elasticsearch.bat
    5.配置檔案:elasticsearch-rtfelasticsearch-rtf-masterconfigelasticsearch.yml
檢視elasticsearch安裝情況.png

2. elasticsearch兩個重要外掛:head和kibana的安裝

head外掛相當於Navicat,用於管理資料庫,基於瀏覽器

https://github.com/mobz/elasticsearch-head

Running with built in server

git clone git://github.com/mobz/elasticsearch-head.git
cd elasticsearch-head
npm install
npm run start
open http://localhost:9100/

配置elasticsearch與heade互通

head安裝完成

kibana.bat

kibana.png

2. elasticsearch基礎概念

  1. 叢集:一個或多個節點組織在一起
  2. 節點:一個叢集中的一臺伺服器
  3. 分片:索引劃分為多份的能力,允許水平分割,擴充套件容量,多個分片響應請求
  4. 副本:分片的一份或多分,一個節點失敗,其他節點頂上

|index | 資料庫|
|type | 表|
|document | 行|
|fields | 列|

集合搜尋和儲存:增加了五種方法:
OPTIONS & PUT & DELETE & TRACE & CONNECT

3. 倒排索引:

倒排索引
倒排索引

倒排索引待解決的問題:

倒排索引
建立索引
head檢視索引.png

4. elasticsearch命令

PUT lagou/job/1
1為id

PUT lagou/job/
不指明id自動生成uuid。

修改部分欄位
POST lagou/job/1/_update

DELETE lagou/job/1

elasticserach批量操作:

查詢index為testdb下的job1表的id為1和job2表的id為2的資料

GET _mget
{
    "docs":[
    {
    "_index":"testdb",
    "_type":"job1",
    "_id":1
    },
    {
    "_index":"testdb",
    "_type":"job2",
    "_id":2
    }
    ]
}

index已經指定了,所有在doc中就不用指定了

GET testdb/_mget{
    "docs":[
    {
    "_type":"job1",
    "_id":1
    },
    {
    "_type":"job2",
    "_id":2
    }
    ]
}

連type都一樣,只是id不一樣

GET testdb/job1/_megt
{
    "docs":[
    {
    "_id":1
    },
    {
    "_id":2
    }
    ]
}

或者繼續簡寫

GET testdb/job1/_megt
{
    "ids":[1,2]
}

elasticsearch的bulk批量操作:可以合併多個操作,比如index,delete,update,create等等,包括從一個索引到另一個索引:

  • action_and_meta_data
  • option_source
  • action_and_meta_data
  • option_source
  • ….
  • action_and_meta_data
  • option_source

每個操作都是由兩行構成,除了delete除外,由元資訊行和資料行組成
注意資料不能美化,即只能是兩行的形式,而不能是經過解析的標準的json排列形式,否則會報錯

POST _bulk
{"index":...}
{"field":...}

elasticserach的mapping對映

elasticserach的mapping對映:建立索引時,可以預先定義欄位的型別以及相關屬性,每個欄位定義一種型別,屬性比mysql裡面豐富,前面沒有傳入,因為elasticsearch會根據json源資料來猜測是什麼基礎型別。M挨批評就是我們自己定義的欄位的資料型別,同時告訴elasticsearch如何索引資料以及是否可以被搜尋。
作用:會讓索引建立的更加細緻和完善,對於大多數是不需要我們自己定義

相關屬性的配置

  • String型別: 兩種text keyword。text會對內部的內容進行分析,索引,進行倒排索引等,為設定為keyword則會當成字串,不會被分析,只能完全匹配才能找到String。 在es5已經被廢棄了
  • 日期型別:date 以及datetime等
  • 資料型別:integer long double等等
  • bool型別
  • binary型別
  • 複雜型別:object nested
  • geo型別:geo-point地理位置
  • 專業型別:ip competition
  • object :json裡面內建的還有下層{}的物件
  • nested:陣列形式的資料

elasticserach查詢:

大概分為三類:

  • 基本查詢:
  • 組合查詢:
  • 過濾:查詢同時,通過filter條件在不影響打分的情況下篩選資料

match查詢:

後面為關鍵詞,關於python的都會提取出來,match查詢會對內容進行分詞,並且會自動對傳入的關鍵詞進行大小寫轉換,內建ik分詞器會進行切分,如python網站,只要搜到存在的任何一部分,都會返回
GET lagou/job/_search

{
    "query":{
        "match":{
            "title":"python"
        }
    }
}

term查詢

區別,對傳入的值不會做任何處理,就像keyword,只能查包含整個傳入的內容的,一部分也不行,只能完全匹配

terms查詢

title裡傳入多個值,只要有一個匹配,就會返回結果

控制查詢的返回數量

GET lagou/_serach
{
    "query":{
        "match":{
            "title":"python"
        }
    },
    "form":1,
    "size":2
}

通過這裡就可以完成分頁處理洛,從第一條開始查詢兩條

match_all 返回所有
GET lagou/_search
{
“query”:{
“match_all”:{}
}
}

match_phrase查詢 短語查詢

GET lagou/_search
{
    "query":{
        "match_phrase":{
            "title":{
                "query":"python系統",
                "slop":6
            }
        }
    }
}

python系統,將其分詞,分為詞條,滿足詞條裡面的所有詞才會返回結果,slop引數說明兩個詞條之間的最小距離

multi_match查詢

比如可以指定多個欄位,比如查詢title和desc這兩個欄位包含python的關鍵詞文件

GET lagou/_search
{
    "query":{
        "multi_match":{
            "query":"python",
            "fileds":["title^3","desc"]
        }
    }
}

query為要查詢的關鍵詞 fileds在哪些欄位裡查詢關鍵詞,只要其中某個欄位中出現了都返回

^3的意思為設定權重,在title中找到的權值為在desc欄位中找到的權值的三倍

指定返回欄位

GET lagou/_search{
    "stored_fields":["title","company_name"],
    "query":{
        "match":{
            "title":"pyhton"
        }
    }
}

通過sort把結果排序

GET lagou/_search
{
    "query";{
        "match_all":{}
    },
    "sort":[{
        "comments":{
            "order":"desc"
        }
    }]
}

sort是一個陣列,裡面是一個字典,key就是要sort的欄位,asc desc是升序降序的意思

查詢範圍 range查詢
GET lagou/_search
{
“query”;{
“range”:{
“comments”:{
“gte”:10,
“lte”:20,
“boost”:2.0
}
}
}
}

range是在query裡面的,boost是權重,gte lte是大於等於 小於等於的意思
對時間的範圍查詢,則是以字串的形式傳入

wildcard模糊查詢,可以使用萬用字元
*

組合查詢:bool查詢

bool查詢包括了must should must_not filter來完成
格式如下:

bool:{
    "filter":[],
    "must":[],
    "should":[],
    "must_not":[],
}

5. 把爬取的資料儲存至elasticsearch

class ElasticsearchPipeline(object):
    #將資料寫入到es中

    def process_item(self, item, spider):
        #將item轉換為es的資料
        item.save_to_es()

        return item

elasticsearch-dsl-py

High level Python client for Elasticsearch

pip install elasticsearch-dsl

items.py 中將資料儲存至es

 def save_to_es(self):
        article = ArticleType()
        article.title = self[`title`]
        article.create_date = self["create_date"]
        article.content = remove_tags(self["content"])
        article.front_image_url = self["front_image_url"]
        if "front_image_path" in self:
            article.front_image_path = self["front_image_path"]
        article.praise_nums = self["praise_nums"]
        article.fav_nums = self["fav_nums"]
        article.comment_nums = self["comment_nums"]
        article.url = self["url"]
        article.tags = self["tags"]
        article.meta.id = self["url_object_id"]

        article.suggest = gen_suggests(ArticleType._doc_type.index, ((article.title,10),(article.tags, 7)))

        article.save()

        redis_cli.incr("jobbole_count")

        return

6. elasticsearch結合django搭建搜尋引擎

獲取elasticsearch的查詢介面

 body={
                    "query":{
                        "multi_match":{
                            "query":key_words,
                            "fields":["tags", "title", "content"]
                        }
                    },
                    "from":(page-1)*10,
                    "size":10,
                    "highlight": {
                        "pre_tags": [`<span class="keyWord">`],
                        "post_tags": [`</span>`],
                        "fields": {
                            "title": {},
                            "content": {},
                        }
                    }
                }

使django與其互動。

搜尋介面
結果介面


相關文章