景點(diǎn)打卡助手(二)

前一篇文章描述了數(shù)據(jù)的獲?。ú杉┖皖A(yù)處理,本文介紹數(shù)據(jù)的存儲

存儲設(shè)計(jì)

為了實(shí)現(xiàn)更加快速便捷的數(shù)據(jù)訪問,需要對數(shù)據(jù)存儲方式進(jìn)行一定的設(shè)計(jì)。雖然目前只有251個景點(diǎn),但是系統(tǒng)應(yīng)該采用適用考慮更大規(guī)模數(shù)據(jù)的設(shè)計(jì)。

設(shè)計(jì)目標(biāo)

存儲的核心是索引,索引設(shè)計(jì)的關(guān)鍵就是選擇合適的索引技術(shù)。根據(jù)我們的目標(biāo):

  1. 景點(diǎn)查找,需求可以理解為根據(jù)名稱、地區(qū)、排名、是否可用等條件進(jìn)行檢索
  2. 附近景點(diǎn):即為需要根據(jù)經(jīng)緯度進(jìn)行查找
  3. 我是否來過?這個最簡單,需要一張記錄表。
    總的來說,系統(tǒng)需要支持根據(jù)關(guān)鍵詞(名稱或地區(qū))、時間范圍、true/false、經(jīng)緯度等查詢。顯然,這需要用到全文索引、范圍索引、經(jīng)緯度索引,當(dāng)然還有哈希索引,這基本是所有系統(tǒng)必備的,它實(shí)現(xiàn)的就是根據(jù)ID進(jìn)行查找。

存儲選型

傳統(tǒng)的關(guān)系數(shù)據(jù)庫基本上支持范圍索引和哈希索引,盡管新版本也開始支持全文,但是畢竟這些數(shù)據(jù)庫大部分是國外的,對中文支持不好。

ElasticSearch(簡稱ES,別和EcmaScript搞混了)是一個很直接的選擇,能夠支持所有四種索引,并且建索引的過程是高度可控的。ES提供了RESTFul訪問接口,可以方便快速構(gòu)建Web應(yīng)用。

數(shù)據(jù)庫準(zhǔn)備

ES安裝部署

安裝非常簡單,到官網(wǎng)下載壓縮包,解壓后即可運(yùn)行。


文件夾結(jié)構(gòu)

啟動:

  bin\elasticsearch.bat

通常需要改一下配置文件 config/elasticsearch.yml。主要配置項(xiàng)如下:

cluster.name: es7-2019
node.name: node-1
path.data: data
path.logs: logs
network.host: 127.0.0.1
http.port: 9200
xpack.ml.enabled: false
http.cors.enabled: true 
http.cors.allow-origin: "*"

最底下的http.cors. 配置是為了后面安裝的head插件跨域訪問的,該插件相當(dāng)于是ES的管理界面。

head插件安裝

在2.x以前版本,head插件是放在ES的plugins目錄下,使用http://localhost:9200/_plugin/head訪問。版本5以后head插件需要單獨(dú)運(yùn)行。

參考這里 下載安裝運(yùn)行head插件。該項(xiàng)目基于npm+grunt,需要提前安裝nodejs。

由于前面已經(jīng)配置了ES支持跨域請求,所以可以看到看到界面:


head插件界面-概覽

這是我已經(jīng)寫入數(shù)據(jù)(place庫)后的樣子??梢钥吹较到y(tǒng)中有兩個索引(相當(dāng)于數(shù)據(jù)庫)place和bank。集群健康狀態(tài)是黃色,因?yàn)閎ank索引聲明了1一個副本,但是集群只有一個節(jié)點(diǎn)(node-1),只有一份數(shù)據(jù)。place索引是完全正常的,它分為5塊(12345),沒有副本。

head插件界面-基本查詢

圖中顯示了采用基本采用,loc字段匹配“延慶”的結(jié)果。這正式全文索引實(shí)現(xiàn)的效果,因?yàn)樗鼤Α把討c區(qū)”、“北京延慶”等進(jìn)行拆分,獲得“延慶”詞條。檢索時是基于該詞條進(jìn)行查找的。

分詞插件

ES 7版本自帶了一個中文分詞器 smartcn,效果還未檢驗(yàn)。之前一般用IK分詞器,這個插件需要單獨(dú)安裝。安裝比較簡單,參考https://github.com/medcl/elasticsearch-analysis-ik

數(shù)據(jù)處理入庫

基于存儲設(shè)計(jì),現(xiàn)在來實(shí)現(xiàn)數(shù)據(jù)入庫建索引。

文檔結(jié)構(gòu)

基于之前采集的信息和需要查詢的字段,設(shè)計(jì)如下文檔結(jié)構(gòu):

{  "loc": "北京.豐臺", 
    "name": "北戲書館", 
    "img": "http://zglynk.com/ITS/upload/areaIcon/3512bab5-3437-4821-bb48-edea8a185dfc.jpg", 
    "url": "http://zglynk.com/ITS/wechatPortalInfo/goAreaDetail.action?id=370", 
    "price": 20, 
    "stop": false, 
    "detail": "不限次 2018.11.1-2019.12.31(每周六接待)", 
    "rank": null, 
    "times": 0, 
    "phone": "010-67572221-2197、18612500357", 
    "time": "每周六19:00-21:00   2018.11.1-2019.12.31", 
    "geo": [116.377354, 39.85597 ] 
}

ES中對于記錄唯一標(biāo)識_id是在整個文檔的外層。_id采用原網(wǎng)站的id,如果不存在,由ES生成一個UUID。

ES Mapping

ES默認(rèn)會自動識別文檔字段類型,建立相應(yīng)的索引,但是對于一些文本和經(jīng)緯度,由于檢索方式多樣,因此需要自己定制。索引設(shè)置index-setting.json如下:

{
    "properties":{
        "name": {"type": "text", "analyzer": "ik_smart"},
        "detail": {"type": "text", "analyzer": "smartcn"},
        "loc":  {"type": "text", "analyzer": "ik_smart"},
        "img": {"type":  "text", "index": false},
        "url": {"type": "text" , "index": false},
        "rank": {"type": "text", "analyzer": "keyword"},
        "geo": {"type": "geo_point"}
    }
}

這里對name/detail/loc三個字段采用了全文檢索。不過為了試驗(yàn)分詞器效果,我分別采用了smartcn和IK。對于img和url字段,由于不需要檢索,因此不建索引。對于rank字段,它本身就是一個詞(2A 3A),因此類型是keyword。geo字段設(shè)置類型為geo_point,ES為該類型簡歷geohash索引,支持經(jīng)緯度范圍查詢。

注意,一般的數(shù)值、bool字段不需要特殊設(shè)置,ES會自動建立合適的索引。另外,ES還有很多參數(shù),包括_all _source、多字段、嵌套字段、數(shù)組等,要想用好,通讀一遍官方文檔很重要!

創(chuàng)建索引

索引基本設(shè)置:index-setting.json

{
    "settings" : {
        "index" : {
            "number_of_shards" : 5, 
            "number_of_replicas" : 0 
        }
    }
}

本自己本機(jī)做測試,沒有副本,分區(qū)也較少。在數(shù)據(jù)規(guī)模較大時,應(yīng)該設(shè)置較多的shard數(shù)。同時為了數(shù)據(jù)安全,應(yīng)該設(shè)置1-2個副本(前提是分布式集群部署)

通過curl命令創(chuàng)建:

host=localhost:9200
indexn=place
HEADER="Content-Type: application/json"
PREFIX="http://$host/$indexn"
curl -XPUT -H "$HEADER" $PREFIX -d "@index-setting.json"
curl -XPUT -H "$HEADER" ${PREFIX}/_mapping -d "@index-mapping.json"

小技巧:使用curl命令的 -d "@filename" 可以將復(fù)雜的body參數(shù)寫在文件里面。

另外,我用的ES 7版本提示必須要加Header,默認(rèn)的Content-Type: application/x-www-form-urlencoded 是不支持的。

數(shù)據(jù)處理與提交

將之前生成獲取的數(shù)據(jù),可以很容易地生成相應(yīng)的文檔格式。ES入庫可以一條一條執(zhí)行PUT請求,也可以使用它的bulk API。

為了使用bulk API,先將數(shù)據(jù)生成xjson格式:

{"index": {"_id": "370", "_index": "place"}}
{"loc": "北京.豐臺", "name": "北戲書館", "img": "http://zglynk.com/ITS/upload/areaIcon/3512bab5-3437-4821-bb48-edea8a185dfc.jpg", "url": "http://zglynk.com/ITS/wechatPortalInfo/goAreaDetail.action?id=370", "price": 20, "stop": false, "detail": "不限次 2018.11.1-2019.12.31(每周六接待)", "rank": null, "times": 0, "phone": "010-67572221-2197、18612500357", "time": "每周六19:00-21:00   2018.11.1-2019.12.31", "geo": [116.377354, 39.85597]}
{"index": {"_index": "place"}}
{"loc": "豐臺區(qū)", "name": "豐臺雪鄉(xiāng)冰雪嘉年華", "price": 120, "stop": true, "detail": "接待結(jié)束", "rank": null, "times": 0}

創(chuàng)建索引時,每條數(shù)據(jù)分為2行,第一行指明操作及索引名和_id,第二行是需要寫入的文檔。換行采用\n。

為了生成這個格式,python函數(shù):

def writeJsonArray(arr, filename):
    with open(filename, 'w') as f:
        for item in arr:
            f.write(json.dumps(item, ensure_ascii = False)) #不要格式化
            f.write('\n') #添加換行符

最后,提交整個文件給ES:

curl -s -H "Content-Type: application/x-ndjson" -XPOST localhost:9200/_bulk --data-binary "@list2.json"

小節(jié)

通過ES可以很方便地檢索查詢數(shù)據(jù)。不過ES本身是近實(shí)時的,采用最終一致性模型,因此不適合做一些事務(wù)類的業(yè)務(wù),因此主要用于數(shù)據(jù)查詢分析,尤其是全文檢索、日志分析等。

下一步

下一步將基于vue.js框架,構(gòu)建基本查詢檢索界面。通過openlayers或地圖平臺(如高德)API 進(jìn)行地圖展示。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容