電商網(wǎng)站技術(shù)要點剖析

電商網(wǎng)站技術(shù)要點剖析

商業(yè)模式

  1. B2B - 商家對商家址貌,交易雙方都是企業(yè)(商家)脚翘,最典型的案例就是阿里巴巴。
  2. C2C - 個人對個人炎咖,例如:淘寶赃泡、人人車寒波。
  3. B2C - 商家對個人,例如:唯品會升熊,聚美優(yōu)品俄烁。
  4. C2B - 個人對商家,先有消費者提出需求级野,后有商家按需求組織生產(chǎn)页屠,例如: 尚品宅配。
  5. O2O - 線上到線下勺阐,將線下的商務(wù)機會與互聯(lián)網(wǎng)結(jié)合卷中,讓互聯(lián)網(wǎng)成為線下交易的平臺矛双,例如:美團外賣渊抽、餓了么。
  6. B2B2C - 商家對商家對個人议忽,例如:天貓懒闷、京東。

需求要點

  1. 用戶端
    • 首頁(商品分類栈幸、廣告輪播愤估、滾動快訊、瀑布加載速址、推薦玩焰、折扣、熱銷芍锚、……)

    • 用戶(登錄(第三方登錄)昔园、注冊、注銷并炮、自服務(wù)(個人信息默刚、瀏覽歷史、收貨地址逃魄、……))

    • 商品(分類荤西、列表、詳情伍俘、搜索邪锌、熱門搜索、搜索歷史癌瘾、添加到購物車觅丰、收藏、關(guān)注柳弄、……)

    • 購物車(查看舶胀、編輯(修改數(shù)量概说、刪除商品、清空))

    • 訂單(提交訂單(支付)嚣伐、歷史訂單糖赔、訂單詳情、訂單評價轩端、……)

  2. 管理端
    • 核心業(yè)務(wù)實體的CRUD
    • 定時任務(wù)(周期性和非周期性)
    • 報表功能(Excel放典、PDF、ECharts)
    • 權(quán)限控制(RBAC)
    • 業(yè)務(wù)流轉(zhuǎn)(Activity基茵、Airflow奋构、Spiff、自定義)
    • 三方服務(wù)(地圖拱层、短信弥臼、物流、支付根灯、實名認證径缅、天氣、監(jiān)控烙肺、……)

提示:可以通過思維導(dǎo)圖來進行需求的整理纳猪,思維導(dǎo)圖上的每個葉子節(jié)點都是不可再拆分的功能,而且都是動詞桃笙。

物理模型設(shè)計

兩個概念:SPU(Standard Product Unit)和SKU(Stock Keeping Unit)氏堤。

  • SPU:iPhone 6s
  • SKU:iPhone 6s 64G 土豪金

第三方登錄

第三方登錄是指利用第三方網(wǎng)站(通常是知名社交網(wǎng)站)的賬號進行登錄驗證,比如國內(nèi)的 QQ搏明、微博鼠锈,國外的Google、Facebook等熏瞄,第三方登錄大部分都是使用OAuth脚祟,它是一個關(guān)于授權(quán)的開放網(wǎng)絡(luò)標準,得到了廣泛的應(yīng)用强饮,目前通常使用的是2.0版本由桌。關(guān)于OAuth的基礎(chǔ)知識,可以閱讀阮一峰老師的《理解OAuth 2.0》邮丰。

OAuth 2.0授權(quán)流程

  1. 用戶打開客戶端以后行您,客戶端要求用戶(資源所有者)給予授權(quán)。
  2. 用戶(資源所有者)同意給予客戶端授權(quán)剪廉。
  3. 客戶端使用上一步獲得的授權(quán)娃循,向認證服務(wù)器申請訪問令牌。
  4. 認證服務(wù)器對客戶端進行認證以后斗蒋,發(fā)放訪問令牌捌斧。
  5. 客戶端使用訪問令牌向資源服務(wù)器申請獲取資源笛质。
  6. 資源服務(wù)器確認訪問令牌無誤,同意向客戶端開放資源捞蚂。

如果使用微博登錄進行接入妇押,其具體步驟可以參考微博開放平臺上的“微博登錄接入”文檔。使用QQ登錄進行接入姓迅,需要首先注冊成為QQ互聯(lián)開發(fā)者并通過審核敲霍,具體的步驟可以參考QQ互聯(lián)上的“接入指南”,具體的步驟可以參考“網(wǎng)站開發(fā)流程”丁存。

提示:在Gitbook上面有一本名為《Django博客入門》的書以Github為例介紹了第三方賬號登錄肩杈,有興趣的可以自行閱讀。

通常電商網(wǎng)站在使用第三方登錄時解寝,會要求與網(wǎng)站賬號進行綁定或者根據(jù)獲取到的第三方賬號信息(如:手機號)自動完成賬號綁定扩然。

緩存預(yù)熱和查詢緩存

緩存預(yù)熱

所謂緩存預(yù)熱,是指在啟動服務(wù)器時將數(shù)據(jù)提前加載到緩存中编丘,為此可以在Django應(yīng)用的apps.py模塊中編寫AppConfig的子類并重寫ready()方法与学,代碼如下所示。

import pymysql

from django.apps import AppConfig
from django.core.cache import cache

SELECT_PROVINCE_SQL = 'select distid, name from tb_district where pid is null'


class CommonConfig(AppConfig):
    name = 'common'

    def ready(self):
        conn = pymysql.connect(host='1.2.3.4', port=3306,
                               user='root', password='pass',
                               database='db', charset='utf8',
                               cursorclass=pymysql.cursors.DictCursor)
        try:
            with conn.cursor() as cursor:
                cursor.execute(SELECT_PROVINCE_SQL)
                provinces = cursor.fetchall()
                cache.set('provinces', provinces)
        finally:
            conn.close()

接下來嘉抓,還需要在應(yīng)用的__init__.py中編寫下面的代碼。

default_app_config = 'common.apps.CommonConfig'

或者在項目的settings.py文件中注冊應(yīng)用晕窑。

INSTALLED_APPS = [
    ...
    'common.apps.CommonConfig',
    ...
]

查詢緩存

自定義裝飾器實現(xiàn)查詢結(jié)果的緩存抑片。

from pickle import dumps
from pickle import loads

from django.core.cache import caches

MODEL_CACHE_KEY = 'project:modelcache:%s'


def my_model_cache(key, section='default', timeout=None):
    """實現(xiàn)模型緩存的裝飾器"""

    def wrapper1(func):

        def wrapper2(*args, **kwargs):
            real_key = '%s:%s' % (MODEL_CACHE_KEY % key, ':'.join(map(str, args)))
            serialized_data = caches[section].get(real_key)
            if serialized_data:
                data = loads(serialized_data)
            else:
                data = func(*args, **kwargs)
                cache.set(real_key, dumps(data), timeout=timeout)
            return data

        return wrapper2

    return wrapper1
@my_model_cache(key='provinces')
def get_all_provinces():
    return list(Province.objects.all())

購物車實現(xiàn)

問題一:已登錄用戶的購物車放在哪里?未登錄用戶的購物車放在哪里杨赤?

class CartItem(object):
    """購物車中的商品項"""

    def __init__(self, sku, amount=1, selected=False):
        self.sku = sku
        self.amount = amount
        self.selected = selected

    @property
    def total(self):
        return self.sku.price * self.amount


class ShoppingCart(object):
    """購物車"""

    def __init__(self):
        self.items = {}
        self.index = 0

    def add_item(self, item):
        if item.sku.id in self.items:
            self.items[item.sku.id].amount += item.amount
        else:
            self.items[item.sku.id] = item

    def remove_item(self, sku_id):
        if sku_id in self.items:
            self.items.remove(sku_id)

    def clear_all_items(self):
        self.items.clear()

    @property
    def cart_items(self):
        return self.items.values()

    @property
    def cart_total(self):
        total = 0
        for item in self.items.values():
            total += item.total
        return total

已登錄用戶的購物車可以放在數(shù)據(jù)庫中(可以先在Redis中緩存)敞斋;未登錄用戶的購物車可以保存在Cookie、localStorage或sessionStorage中(減少服務(wù)器端內(nèi)存開銷)疾牲。

{
    '1001': {sku: {...}, 'amount': 1, 'selected': True}, 
    '1002': {sku: {...}, 'amount': 2, 'selected': False},
    '1003': {sku: {...}, 'amount': 3, 'selected': True},
}
request.get_signed_cookie('cart')

cart_base64 = base64.base64encode(pickle.dumps(cart))
response.set_signed_cookie('cart', cart_base64)

問題二:用戶登錄之后植捎,如何合并購物車?(目前電商應(yīng)用的購物車幾乎都做了持久化處理阳柔,主要是方便在多個終端之間共享數(shù)據(jù))

集成支付功能

問題一:支付信息如何持久化焰枢?(必須保證每筆交易都有記錄)

問題二:如何接入支付寶?(接入其他平臺基本類似)

  1. 螞蟻金服開放平臺舌剂。
  2. 入駐平臺济锄。
  3. 開發(fā)者中心
  4. 文檔中心霍转。
  5. SDK集成 - PYPI鏈接荐绝。
  6. API列表

[圖片上傳失敗...(image-6e4e8c-1554952013122)]

配置文件:

ALIPAY_APPID = '......'
ALIPAY_URL = 'https://openapi.alipaydev.com/gateway.do'
ALIPAY_DEBUG = False

獲得支付鏈接(發(fā)起支付):

# 創(chuàng)建調(diào)用支付寶的對象
alipay = AliPay(
    # 在線創(chuàng)建應(yīng)用時分配的ID
    appid=settings.ALIPAY_APPID,
    app_notify_url=None,
    # 自己應(yīng)用的私鑰
    app_private_key_path=os.path.join(
        os.path.dirname(os.path.abspath(__file__)), 
        'keys/app_private_key.pem'),
    # 支付寶的公鑰
    alipay_public_key_path=os.path.join(
        os.path.dirname(os.path.abspath(__file__)), 
        'keys/alipay_public_key.pem'),
    sign_type='RSA2',
    debug=settings.ALIPAY_DEBUG
)
# 調(diào)用獲取支付頁面操作
order_info = alipay.api_alipay_trade_page_pay(
    out_trade_no='...',
    total_amount='...',
    subject='...',
    return_url='http://...'
)
# 生成完整的支付頁面URL
alipay_url = settings.ALIPAY_URL + '?' + order_info
return JsonResponse({'alipay_url': alipay_url})

通過上面返回的鏈接可以進入支付頁面避消,支付完成后會自動跳轉(zhuǎn)回上面代碼中設(shè)定好的項目頁面低滩,在該頁面中可以獲得訂單號(out_trade_no)召夹、支付流水號(trade_no)、交易金額(total_amount)和對應(yīng)的簽名(sign)并請求后端驗證和保存交易結(jié)果恕沫,代碼如下所示:

# 創(chuàng)建調(diào)用支付寶的對象
alipay = AliPay(
    # 在線創(chuàng)建應(yīng)用時分配的ID
    appid=settings.ALIPAY_APPID,
    app_notify_url=None,
    # 自己應(yīng)用的私鑰
    app_private_key_path=os.path.join(
        os.path.dirname(os.path.abspath(__file__)), 
        'keys/app_private_key.pem'),
    # 支付寶的公鑰
    alipay_public_key_path=os.path.join(
        os.path.dirname(os.path.abspath(__file__)), 
        'keys/alipay_public_key.pem'),
    sign_type='RSA2',
    debug=settings.ALIPAY_DEBUG
)
# 請求參數(shù)(假設(shè)是POST請求)中包括訂單號戳鹅、支付流水號、交易金額和簽名
params = request.POST.dict()
# 調(diào)用驗證操作
if alipay.verify(params, params.pop('sign')):
    # 對交易進行持久化操作

支付寶的支付API還提供了交易查詢昏兆、交易結(jié)算枫虏、退款、退款查詢等一系列的接口爬虱,可以根據(jù)業(yè)務(wù)需要進行調(diào)用隶债,此處不再進行贅述。

秒殺和超賣

  1. 秒殺:秒殺是通常意味著要在很短的時間處理極高的并發(fā)跑筝,系統(tǒng)在短時間需要承受平時百倍以上的流量死讹,因此秒殺架構(gòu)是一個比較復(fù)雜的問題,其核心思路是流量控制和性能優(yōu)化曲梗,需要從前端(通過JavaScript實現(xiàn)倒計時赞警、避免重復(fù)提交和限制頻繁刷新)到后臺各個環(huán)節(jié)的配合。流量控制主要是限制只有少部分流量進入服務(wù)后端(畢竟最終只有少部分用戶能夠秒殺成功)虏两,同時在物理架構(gòu)上使用緩存(一方面是因為讀操作多寫操作少愧旦;另外可以將庫存放在Redis中,利用DECR原語實現(xiàn)減庫存定罢;同時也可以利用Redis來進行限流笤虫,道理跟限制頻繁發(fā)送手機驗證碼是一樣的)和消息隊列(消息隊列最為重要的作用就是“削峰”和“上下游節(jié)點解耦合”)來進行優(yōu)化;此外還要采用無狀態(tài)服務(wù)設(shè)計祖凫,這樣才便于進行水平擴展(通過增加設(shè)備來為系統(tǒng)擴容)琼蚯。
  2. 超賣現(xiàn)象:比如某商品的庫存為1,此時用戶1和用戶2并發(fā)購買該商品惠况,用戶1提交訂單后該商品的庫存被修改為0遭庶,而此時用戶2并不知道的情況下提交訂單,該商品的庫存再次被修改為-1這就是超賣現(xiàn)象稠屠。解決超賣現(xiàn)象有三種常見的思路:
    • 悲觀鎖控制:查詢商品數(shù)量的時候就用select ... for update對數(shù)據(jù)加鎖峦睡,這樣的話用戶1查詢庫存時,用戶2因無法讀取庫存數(shù)量被阻塞完箩,直到用戶1提交或者回滾了更新庫存的操作后才能繼續(xù)赐俗,從而解決了超賣問題。但是這種做法對并發(fā)訪問量很高的商品來說性能太過糟糕弊知,實際開發(fā)中可以在庫存小于某個值時才考慮加鎖阻逮,但是總的來說這種做法不太可取。
    • 樂觀鎖控制:查詢商品數(shù)量不用加鎖秩彤,更新庫存的時候設(shè)定商品數(shù)量必須與之前查詢數(shù)量相同才能更新叔扼,否則說明其他事務(wù)已經(jīng)更新了庫存事哭,必須重新發(fā)出請求。這種做法要求事務(wù)隔離級別為可重復(fù)讀瓜富,否則仍然會產(chǎn)生問題鳍咱。
    • 嘗試減庫存:將上面的查詢(select)和更新(update)操作合并為一條SQL操作,更新庫存的時候与柑,在where篩選條件中加上庫存>=購買數(shù)量庫存-購買數(shù)量>=0的條件谤辜。

提示:有興趣的可以自己在知乎上看看關(guān)于這類問題的討論。

靜態(tài)資源管理

靜態(tài)資源的管理可以自己架設(shè)文件服務(wù)器或者分布式文件服務(wù)器(FastDFS)价捧,但是一般的項目中沒有必要這樣做而且效果未必是最好的丑念,我們建議使用云存儲服務(wù)來管理網(wǎng)站的靜態(tài)資源,國內(nèi)外的云服務(wù)提供商如亞馬遜结蟋、阿里云脯倚、騰訊云、七牛嵌屎、LeanCloud推正、Bmob等都提供了非常優(yōu)質(zhì)的云存儲服務(wù),而且價格也是一般公司可以接受的宝惰≈查牛可以參考《在阿里云OSS上托管靜態(tài)網(wǎng)站》一文來完成對網(wǎng)站靜態(tài)資源的管理,代碼相關(guān)的內(nèi)容可以參考阿里云的對象存儲 OSS開發(fā)人員指南掌测。

全文檢索

方案選擇

  1. 使用數(shù)據(jù)庫的模糊查詢功能 - 效率低内贮,每次需要全表掃描,不支持分詞汞斧。
  2. 使用數(shù)據(jù)庫的全文檢索功能 - MySQL 5.6以前只適用于MyISAM引擎,檢索操作和其他的DML操作耦合在數(shù)據(jù)庫中什燕,可能導(dǎo)致檢索操作非常緩慢粘勒,數(shù)據(jù)量達到百萬級性能顯著下降,查詢時間很長屎即。
  3. 使用開源搜索引擎 - 索引數(shù)據(jù)和原始數(shù)據(jù)分離庙睡,可以使用ElasticSearch或Solr來提供外置索引服務(wù),如果不考慮高并發(fā)的全文檢索需求技俐,純Python的Whoosh也可以考慮乘陪。

ElasticSearch

ElasticSearch既是一個分布式文檔數(shù)據(jù)庫又是一個高可擴展的開源全文搜索和分析引擎,它允許存儲雕擂、搜索和分析大量的數(shù)據(jù)啡邑,并且這個過程是近實時的。它通常被用作底層引擎和技術(shù)井赌,為復(fù)雜的搜索功能和要求提供動力谤逼,大家熟知的維基百科贵扰、Stack-Overflow、Github都使用了ElasticSearch流部。

ElasticSearch的底層是開源搜索引擎Lucene戚绕,但是直接用Lucene會非常麻煩,必須自己編寫代碼去調(diào)用它的接口而且只支持Java語言枝冀。ElasticSearch相當于對Lucene進行了一次全面的封裝舞丛,提供了REST風(fēng)格的API接口,通過基于HTTP協(xié)議的訪問方式屏蔽了編程語言的差異果漾。ElasticSearch會為數(shù)據(jù)構(gòu)建倒排索引球切,但是ElasticSearch內(nèi)置的分詞器對中文分詞的支持幾乎為零,因此需要通過安裝elasticsearch-analysis-ik插件來提供中文分詞服務(wù)跨晴。

ElasticSearch的安裝和配置可以參考《ElasticSearch之Docker安裝》欧聘。除了ElasticSearch之外,也可以使用Solr端盆、Whoosh等來提供搜索引擎服務(wù)怀骤,基本上Django項目中可以考慮如下兩套方案:

  • haystack(django-haystack / drf-haystack) + whoosh + Jieba
  • haystack (django-haystack / drf-haystack)+ elasticsearch

安裝和使用ElasticSearch

  1. 使用Docker安裝ElasticSearch。

    docker pull elasticsearch:6.5.3
    docker run -d -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms512m -Xmx512m" --name es elasticsearch:6.5.3
    

    說明:上面創(chuàng)建容器時通過-e參數(shù)指定了使用單機模式和Java虛擬機最小最大可用堆空間的大小焕妙,堆空間大小可以根據(jù)服務(wù)器實際能夠提供給ElasticSearch的內(nèi)存大小來決定蒋伦,默認為2G。

  2. 創(chuàng)建數(shù)據(jù)庫焚鹊。

    請求:PUT - http://1.2.3.4:9200/demo

    響應(yīng):

    {
       "acknowledged": true,
       "shards_acknowledged": true,
       "index": "demo"
    }
    
  3. 查看創(chuàng)建的數(shù)據(jù)庫痕届。

    請求:GET - http://1.2.3.4:9200/demo

    響應(yīng):

    {
        "demo": {
            "aliases": {},
            "mappings": {},
            "settings": {
                "index": {
                    "creation_date": "1552213970199",
                    "number_of_shards": "5",
                    "number_of_replicas": "1",
                    "uuid": "ny3rCn10SAmCsqW6xPP1gw",
                    "version": {
                        "created": "6050399"
                    },
                    "provided_name": "demo"
                }
            }
        }
    }
    
  4. 插入數(shù)據(jù)。

    請求:POST - http://1.2.3.4:9200/demo/goods/1/

    請求頭:Content-Type: application/json

    參數(shù):

    {
        "no": "5089253",
        "title": "Apple iPhone X (A1865) 64GB 深空灰色 移動聯(lián)通電信4G手機",
        "brand": "Apple",
        "name": "Apple iPhone X",
        "product": "中國大陸",
        "resolution": "2436 x 1125",
        "intro": "一直以來末患,Apple都心存一個設(shè)想研叫,期待能夠打造出這樣一部iPhone:它有整面屏幕,能讓你在使用時璧针,完全沉浸其中嚷炉,仿佛忘了它的存在。它是如此智能探橱,哪怕輕輕一瞥申屹,都能得到它心有靈犀的回應(yīng)。而這個設(shè)想隧膏,終于隨著iPhone X的到來成為了現(xiàn)實』┘ィ現(xiàn)在,就跟未來見個面吧胞枕。"
    }
    

    響應(yīng):

    {
        "_index": "demo",
        "_type": "goods",
        "_id": "1",
        "_version": 4,
        "result": "created",
        "_shards": {
            "total": 2,
            "successful": 1,
            "failed": 0
        },
        "_seq_no": 3,
        "_primary_term": 1
    }
    
  5. 刪除數(shù)據(jù)杆煞。

    請求:DELETE - http://1.2.3.4:9200/demo/goods/1/

    響應(yīng):

    {
        "_index": "demo",
        "_type": "goods",
        "_id": "1",
        "_version": 2,
        "result": "deleted",
        "_shards": {
            "total": 2,
            "successful": 1,
            "failed": 0
        },
        "_seq_no": 1,
        "_primary_term": 1
    }
    
  6. 更新數(shù)據(jù)。

    請求:PUT - http://1.2.3.4:9200/demo/goods/1/_update

    請求頭:Content-Type: application/json

    參數(shù):

    {
     "doc": {
         "no": "5089253",
         "title": "Apple iPhone X (A1865) 64GB 深空灰色 移動聯(lián)通電信4G手機",
         "brand": "Apple(蘋果)",
         "name": "Apple iPhone X",
         "product": "美國",
         "resolution": "2436 x 1125",
         "intro": "一直以來,Apple都心存一個設(shè)想索绪,期待能夠打造出這樣一部iPhone:它有整面屏幕湖员,能讓你在使用時,完全沉浸其中瑞驱,仿佛忘了它的存在娘摔。它是如此智能,哪怕輕輕一瞥唤反,都能得到它心有靈犀的回應(yīng)凳寺。而這個設(shè)想,終于隨著iPhone X的到來成為了現(xiàn)實⊥蹋現(xiàn)在肠缨,就跟未來見個面吧。"
        }
    }
    

    響應(yīng):

    {
        "_index": "demo",
        "_type": "goods",
        "_id": "1",
        "_version": 10,
        "result": "updated",
        "_shards": {
            "total": 2,
            "successful": 1,
            "failed": 0
        },
        "_seq_no": 9,
        "_primary_term": 1
    }
    
  7. 查詢數(shù)據(jù)盏阶。

    請求:GET - http://1.2.3.4:9200/demo/goods/1/

    響應(yīng):

    {
        "_index": "demo",
        "_type": "goods",
        "_id": "1",
        "_version": 10,
        "found": true,
        "_source": {
            "doc": {
                "no": "5089253",
                "title": "Apple iPhone X (A1865) 64GB 深空灰色 移動聯(lián)通電信4G手機",
                "brand": "Apple(蘋果)",
                "name": "Apple iPhone X",
                "product": "美國",
                "resolution": "2436 x 1125",
                "intro": "一直以來晒奕,Apple都心存一個設(shè)想,期待能夠打造出這樣一部iPhone:它有整面屏幕名斟,能讓你在使用時脑慧,完全沉浸其中,仿佛忘了它的存在砰盐。它是如此智能闷袒,哪怕輕輕一瞥,都能得到它心有靈犀的回應(yīng)岩梳。而這個設(shè)想囊骤,終于隨著iPhone X的到來成為了現(xiàn)實。現(xiàn)在冀值,就跟未來見個面吧也物。"
            }
        }
    }
    

配置中文分詞和拼音插件

  1. 進入Docker容器的plugins目錄。

    docker exec -it es /bin/bash
    
  2. 下載和ElasticSearch版本對應(yīng)的ikpinyin插件列疗。

    cd plugins/
    mkdir ik
    cd ik
    wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.5.3/elasticsearch-analysis-ik-6.5.3.zip
    unzip elasticsearch-analysis-ik-6.5.3.zip
    rm -f elasticsearch-analysis-ik-6.5.3.zip
    cd ..
    mkdir pinyin
    cd pinyin
    wget https://github.com/medcl/elasticsearch-analysis-pinyin/releases/download/v6.5.3/elasticsearch-analysis-pinyin-6.5.3.zip
    unzip elasticsearch-analysis-pinyin-6.5.3.zip
    rm -f elasticsearch-analysis-pinyin-6.5.3.zip
    
  3. 退出容器焦除,重啟ElasticSearch。

    docker restart es
    
  4. 測試中文分詞效果作彤。

    請求:POST - http://1.2.3.4:9200/_analyze

    請求頭:Content-Type: application/json

    參數(shù):

    {
      "analyzer": "ik_smart",
      "text": "中國男足在2022年卡塔爾世界杯預(yù)選賽中勇奪小組最后一名"
    }
    

    響應(yīng):

    {
        "tokens": [
            {
                "token": "中國",
                "start_offset": 0,
                "end_offset": 2,
                "type": "CN_WORD",
                "position": 0
            },
            {
                "token": "男足",
                "start_offset": 2,
                "end_offset": 4,
                "type": "CN_WORD",
                "position": 1
            },
            {
                "token": "在",
                "start_offset": 4,
                "end_offset": 5,
                "type": "CN_CHAR",
                "position": 2
            },
            {
                "token": "2022年",
                "start_offset": 5,
                "end_offset": 10,
                "type": "TYPE_CQUAN",
                "position": 3
            },
            {
                "token": "卡塔爾",
                "start_offset": 10,
                "end_offset": 13,
                "type": "CN_WORD",
                "position": 4
            },
            {
                "token": "世界杯",
                "start_offset": 13,
                "end_offset": 16,
                "type": "CN_WORD",
                "position": 5
            },
            {
                "token": "預(yù)選賽",
                "start_offset": 16,
                "end_offset": 19,
                "type": "CN_WORD",
                "position": 6
            },
            {
                "token": "中",
                "start_offset": 19,
                "end_offset": 20,
                "type": "CN_CHAR",
                "position": 7
            },
            {
                "token": "勇奪",
                "start_offset": 20,
                "end_offset": 22,
                "type": "CN_WORD",
                "position": 8
            },
            {
                "token": "小組",
                "start_offset": 22,
                "end_offset": 24,
                "type": "CN_WORD",
                "position": 9
            },
            {
                "token": "最后",
                "start_offset": 24,
                "end_offset": 26,
                "type": "CN_WORD",
                "position": 10
            },
            {
                "token": "一名",
                "start_offset": 26,
                "end_offset": 28,
                "type": "CN_WORD",
                "position": 11
            }
        ]
    }
    
  5. 測試拼音分詞效果。

    請求:POST - http://1.2.3.4:9200/_analyze

    請求頭:Content-Type: application/json

    參數(shù):

    
    

    響應(yīng):

    {
        "tokens": [
            {
                "token": "zhang",
                "start_offset": 0,
                "end_offset": 0,
                "type": "word",
                "position": 0
            },
            {
                "token": "zxy",
                "start_offset": 0,
                "end_offset": 0,
                "type": "word",
                "position": 0
            },
            {
                "token": "xue",
                "start_offset": 0,
                "end_offset": 0,
                "type": "word",
                "position": 1
            },
            {
                "token": "you",
                "start_offset": 0,
                "end_offset": 0,
                "type": "word",
                "position": 2
            }
        ]
    }
    

全文檢索功能

可以通過GET或者POST請求進行搜索乌逐,下面演示了搜索有“未來”關(guān)鍵詞商品竭讳。

  1. GET - http://120.77.222.217:9200/demo/goods/_search?q=未來

    注意:URL中的中文應(yīng)該要處理成百分號編碼。

    {
        "took": 19,
        "timed_out": false,
        "_shards": {
            "total": 5,
            "successful": 5,
            "skipped": 0,
            "failed": 0
        },
        "hits": {
            "total": 2,
            "max_score": 0.73975396,
            "hits": [
                {
                    "_index": "demo",
                    "_type": "goods",
                    "_id": "1",
                    "_score": 0.73975396,
                    "_source": {
                        "doc": {
                            "no": "5089253",
                            "title": "Apple iPhone X (A1865) 64GB 深空灰色 移動聯(lián)通電信4G手機",
                            "brand": "Apple(蘋果)",
                            "name": "Apple iPhone X",
                            "product": "美國",
                            "resolution": "2436*1125",
                            "intro": "一直以來浙踢,Apple都心存一個設(shè)想绢慢,期待能夠打造出這樣一部iPhone:它有整面屏幕,能讓你在使用時,完全沉浸其中胰舆,仿佛忘了它的存在骚露。它是如此智能,哪怕輕輕一瞥缚窿,都能得到它心有靈犀的回應(yīng)棘幸。而這個設(shè)想,終于隨著iPhone X的到來成為了現(xiàn)實【肓悖現(xiàn)在误续,就跟未來見個面吧。"
                        }
                    }
                },
                {
                    "_index": "demo",
                    "_type": "goods",
                    "_id": "3",
                    "_score": 0.68324494,
                    "_source": {
                        "no": "42417956432",
                        "title": "小米9 透明尊享版 手機 透明尊享 全網(wǎng)通(12GB + 256GB)",
                        "brand": "小米(MI)",
                        "name": "小米(MI)小米9透明",
                        "product": "中國大陸",
                        "resolution": "2340*1080",
                        "intro": "全面透明機身扫茅,獨特科幻機甲風(fēng)蹋嵌,來自未來的設(shè)計。"
                    }
                }
            ]
        }
    }
    

    URL中可用的搜索參數(shù)如下表所示:

    參數(shù) 說明
    q 查詢字符串
    analyzer 分析查詢字符串使用的分詞器
    analyze_wildcard 通配符或者前綴查詢是否被分析葫隙,默認為false
    default_operator 多個條件之間的關(guān)系栽烂,默認為OR,可以修改為AND
    explain 在返回的結(jié)果中包含評分機制的解釋
    fields 只返回索引中指定的列恋脚,多個列中間用逗號隔開
    sort 排序參考的字段腺办,可以用:asc和:desc來指定升序和降序
    timeout 超時時間
    from 匹配結(jié)果的開始值,默認為0
    size 匹配結(jié)果的條數(shù)慧起,默認為10
  2. POST - http://120.77.222.217:9200/demo/goods/_search

    請求頭:Content-Type: application/json

    參數(shù):

    
    

    響應(yīng):

    
    

Django對接ElasticSearch

Python對接ElasticSearch的第三方庫是HayStack菇晃,在Django項目中可以使用django-haystack,通過HayStack可以在不修改代碼對接多種搜索引擎服務(wù)蚓挤。

pip install django-haystack elasticsearch

配置文件:

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

HAYSTACK_CONNECTIONS = {
    'default': {
        # 引擎配置
        'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
        # 搜索引擎服務(wù)的URL
        'URL': 'http://1.2.3.4:9200',
        # 索引庫的名稱
        'INDEX_NAME': 'goods',
    },
}

# 添加/刪除/更新數(shù)據(jù)時自動生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

索引類:

from haystack import indexes


class GoodsIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)

    def get_model(self):
        return Goods

    def index_queryset(self, using=None):
        return self.get_model().objects.all()

編輯text字段的模板(需要放在templates/search/indexes/demo/goods_text.txt):

{{object.title}}
{{object.intro}}

配置URL:

urlpatterns = [
    # ...
    url('search/', include('haystack.urls')),
]

生成初始索引:

python manage.py rebuild_index

說明:可以參考《Django Haystack 全文檢索與關(guān)鍵詞高亮》一文來更深入的了解基于Haystack的全文檢索操作磺送。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市灿意,隨后出現(xiàn)的幾起案子估灿,更是在濱河造成了極大的恐慌,老刑警劉巖缤剧,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件馅袁,死亡現(xiàn)場離奇詭異,居然都是意外死亡荒辕,警方通過查閱死者的電腦和手機汗销,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抵窒,“玉大人弛针,你說我怎么就攤上這事±罨剩” “怎么了削茁?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我茧跋,道長慰丛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任瘾杭,我火速辦了婚禮诅病,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘富寿。我一直安慰自己睬隶,他們只是感情好,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布页徐。 她就那樣靜靜地躺著苏潜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪变勇。 梳的紋絲不亂的頭發(fā)上恤左,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天,我揣著相機與錄音搀绣,去河邊找鬼飞袋。 笑死盾计,一個胖子當著我的面吹牛粹断,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播凿宾,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼麻捻,長吁一口氣:“原來是場噩夢啊……” “哼纲仍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起贸毕,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤郑叠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后明棍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乡革,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年摊腋,在試婚紗的時候發(fā)現(xiàn)自己被綠了沸版。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡兴蒸,死狀恐怖推穷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情类咧,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站痕惋,受9級特大地震影響区宇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜值戳,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一议谷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧堕虹,春花似錦卧晓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至赦政,卻和暖如春胜宇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背恢着。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工桐愉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人掰派。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓从诲,卻偏偏與公主長得像,于是被迫代替她去往敵國和親靡羡。 傳聞我的和親對象是個殘疾皇子系洛,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容