使用 MongoDB 存儲商品分類信息

此文已由做者溫正湖受權網易雲社區發佈。
mongodb

歡迎訪問網易雲社區,瞭解更多網易技術產品運營經驗。數據庫


這是一篇MongoDB官網上的一篇文章,分析了使用MongoDB存儲商品分類信息相比其餘數據庫的優點,並講述瞭如何將其保存到MongoDB中。原址點擊:User case – Product Catalog。MongoDB中文社區有大神已將其翻譯成中文。在此不重複造車,直接轉載。歡迎一塊兒探討。性能優化

關係型數據庫解決方案

上述問題使用傳統的關係型數據庫也能夠解決,好比如下幾種方案架構

針對不一樣商品,建立不一樣的表

好比音樂專輯、電影這2種商品,有一部分共同的屬性,但也有不少自身特有的屬性,能夠建立2個不一樣的表,擁有不一樣的schema。運維

CREATE TABLE `product_audio_album` (
    `sku` char(8) NOT NULL,
    ...
    `artist` varchar(255) DEFAULT NULL,
    `genre_0` varchar(255) DEFAULT NULL,
    `genre_1` varchar(255) DEFAULT NULL,
    ...,
    PRIMARY KEY(`sku`))
...
CREATE TABLE `product_film` (
    `sku` char(8) NOT NULL,
    ...
    `title` varchar(255) DEFAULT NULL,
    `rating` char(8) DEFAULT NULL,
    ...,
    PRIMARY KEY(`sku`))
...

這種作法的主要問題在於分佈式

  • 針對每一個新的商品分類,都須要建立新的表性能

  • 應用程序開發者必須顯式的將請求分發到對應的表上來查詢,一次查詢多種商品實現起來比較麻煩優化

全部商品存儲到單張表

CREATE TABLE `product` (
    `sku` char(8) NOT NULL,
    ...
    `artist` varchar(255) DEFAULT NULL,
    `genre_0` varchar(255) DEFAULT NULL,
    `genre_1` varchar(255) DEFAULT NULL,
    ...
    `title` varchar(255) DEFAULT NULL,
    `rating` char(8) DEFAULT NULL,
    ...,    PRIMARY KEY(`sku`))

將全部的商品存儲到一張表,這張表包含全部商品須要的屬性,不一樣的商品根據須要設置不一樣的屬性,這種方法使得商品查詢比較簡單,而且容許一個查詢跨多種商品,但缺點是浪費的空間比較多。.net

提取公共屬性,多表繼承

CREATE TABLE `product` (
    `sku` char(8) NOT NULL,
    `title` varchar(255) DEFAULT NULL,
    `description` varchar(255) DEFAULT NULL,
    `price`, ...
    PRIMARY KEY(`sku`))

CREATE TABLE `product_audio_album` (
    `sku` char(8) NOT NULL,
    ...
    `artist` varchar(255) DEFAULT NULL,
    `genre_0` varchar(255) DEFAULT NULL,
    `genre_1` varchar(255) DEFAULT NULL,
    ...,
    PRIMARY KEY(`sku`),
    FOREIGN KEY(`sku`) REFERENCES `product`(`sku`))
...
CREATE TABLE `product_film` (
    `sku` char(8) NOT NULL,
    ...
    `title` varchar(255) DEFAULT NULL,
    `rating` char(8) DEFAULT NULL,
    ...,
    PRIMARY KEY(`sku`),
    FOREIGN KEY(`sku`) REFERENCES `product`(`sku`))
...

上述方案將全部商品公共的屬性提取出來,將公共屬性存儲到一張表裏,每種商品根據自身的須要建立新的表,新表裏只存儲該商品特有的信息。翻譯

Entity Attribute Values 形式存儲

全部的數據按照 的3元組的形式存儲,這個方案其實是把關係型數據庫當KV存儲使用,模型簡單,但應對複雜的查詢不是很方便。

ENTITY ATTRIBUTE VALUES
sku_00e8da9b type Audio Album
sku_00e8da9b title A Love Supreme
sku_00e8da9b
sku_00e8da9b artist John Coltrane
sku_00e8da9b genre Jazz
sku_00e8da9b genre General

MongoDB 解決方案

MognoDB 與關係型數據庫不一樣,其無schema,文檔內容能夠很是靈活的定製,能很好的使用上述商品分類存儲的需求; 將商品信息存儲在一個集合裏,集合裏不一樣的商品能夠自定義文檔內容。

好比一個音樂專輯能夠相似以下的文檔結構

{
  sku: "00e8da9b",
  type: "Audio Album",
  title: "A Love Supreme",
  description: "by John Coltrane",
  asin: "B0000A118M",

  shipping: {
    weight: 6,
    dimensions: {
      width: 10,
      height: 10,
      depth: 1
    },
  },

  pricing: {
    list: 1200,
    retail: 1100,
    savings: 100,
    pct_savings: 8
  },

  details: {
    title: "A Love Supreme [Original Recording Reissued]",
    artist: "John Coltrane",
    genre: [ "Jazz", "General" ],
        ...
    tracks: [
      "A Love Supreme Part I: Acknowledgement",
      "A Love Supreme Part II - Resolution",
      "A Love Supreme, Part III: Pursuance",
      "A Love Supreme, Part IV-Psalm"
    ],
  },
}

而一部電影則能夠存儲爲

{
  sku: "00e8da9d",
  type: "Film",
  ...,
  asin: "B000P0J0AQ",

  shipping: { ... },

  pricing: { ... },

  details: {
    title: "The Matrix",
    director: [ "Andy Wachowski", "Larry Wachowski" ],
    writer: [ "Andy Wachowski", "Larry Wachowski" ],
    ...,
    aspect_ratio: "1.66:1"
  },
}

全部商品都擁有一些共同的基本信息,特定的商品能夠根據須要擴展獨有的內容,很是方便; 基於上述模型,MongoDB 也能很好的服務各種查詢。

查詢某個演員參演的全部電影,並按髮型日誌排序

db.products.find({'type': 'Film', 'details.actor': 'Keanu Reeves'}).sort({'details.issue_date', -1})

上述查詢也能夠經過創建索引來加速

db.products.createIndex({ type: 1, 'details.actor': 1, 'details.issue_date': -1 })

查詢標題裏包含特定信息的全部電影

db.products.find({
    'type': 'Film',
    'title': {'$regex': '.*hacker.*', '$options':'i'}}).sort({'details.issue_date', -1})

可創建以下索引來加速查詢

db.products.createIndex({ type: 1, details.issue_date: -1, title: 1 })

擴展

當單個節點沒法知足海量商品信息存儲的需求時,就須要使用MongoDB sharding來擴展,假定大量的查詢都是都會基於商品類型,那麼就可使用商品類型字段來進行分片。

db.shardCollection('products', { key: {type: 1} })

分片時,儘可能使用複合的索引字段,這樣能知足更多的查詢需求,好比基於商品類型以後,還會常常根據商品的風格標籤來查詢,則能夠把商品的標籤字段做爲第二分片key。

db.shardCollection('products', { key: {type: 1, 'details.genre': 1} })

若是某種類型的商品,擁有相同標籤的特別多,則會出現jumbo chunk的問題,致使沒法遷移,能夠進一步的優化分片key,以免這種狀況。

db.shardCollection('products', { key: {type: 1, 'details.genre': 1, sku: 1} })

加入第3分片key以後,即便類型、風格標籤都相同,但其sku信息確定不一樣,就確定不會出現超大的chunk。


網易雲MongoDB 服務爲開發者提供了一站式的 MongoDB 雲端解決方案,包括提供三節點複製集的高可用架構,故障切換,並提供專業的備份、監控以及性能優化方案,完全免除開發者的運維煩惱。點擊可免費試用




網易雲免費體驗館,0成本體驗20+款雲產品! 

更多網易技術、產品、運營經驗分享請點擊


相關文章:
【推薦】 代碼混淆防止APP被反編譯指南
【推薦】 簡單歸納一下《金字塔原理》的主要內容?
【推薦】 分佈式存儲系統可靠性系列二:系統估算示例

相關文章
相關標籤/搜索