MongoDB Schema Design Pattern - Approximation Pattern

用一句簡單的話說

Approximation Pattern 透過儲存不是必要精確的資料來幫助我們減少 db 資源的損耗


場景

  在一些資料數量龐大的場景下資料更新的頻率會很高,當精確的統計數字並不是必須的情況下,可以透過計算大概正確的值來減少資料更新的頻率,場景可以是人口統計、企業數量等等,邏輯通常實作在 application code 裡

以下是 MongoDB official course 以及 documentation 的兩個範例


範例一:

  在一個 e-commerce App 中需要顯示每個產品的平均 rating,因為該產品的 rating 會頻繁更新而且數量龐大容易拖慢速度,為了改善效能,我們犧牲掉一點評分的準確度,在 App logic 加上一個 random number generator 可以隨機產生 1~10 的數字,當數字是 10 時才進行 write 複寫平均 rating

  此時我們將 rating count + 10 以及將新的 rating 分數乘以 10 來更新 rating 資料

{
product_id: 1000,
name: 'a good product',
rating: {
rating_count: 89200,
avg_rating: 4.9
},
price: 300,
store: 'online'
}

// The new rating is 5
// update document when writing
{
product_id: 1000,
name: 'a good product',
rating: {
rating_count: 89200 + 10, // rating count plus 10
avg_rating: (4.9 * 89200 + 5 * 10) / (89200 + 10) // update the average rating
},
price: 300,
store: 'online'
}

結果就是減少了 90% 的寫入頻率,並增加了效能


範例二:

在一個城市人口統計的 App 中,我們在每次人口發生變化時都會新增一個 document

db.population.insertOne({
city: "New Perth",
population: 40000,
date: ISODate("2022-09-15")
})

  但因為人口數量頻繁變化而我們通常又不需要非常精確的人口數字,於是我們決定在人口變化量大於等於 100 的時候才紀錄當下的人口數

let population = 40000
function updateStoredPopulation(curr_population, new_population) {
let population_change = Math.abs(curr_population - new_population)
if (population_change >= 100) {
db.population.insertOne(
{
city: "New Perth",
population: new_population,
date: Date()
}
)
population = new_population
}
}

// output
[
{
city: "New Perth",
population: 40100,
date: ISODate("2024-09-20")
},
{
city: "New Perth",
population: 40200,
date: ISODate("2024-10-01")
},
{
city: "New Perth",
population: 40300,
date: ISODate("2024-10-09")
},
]


  透過上述的兩個例子可以發現,Approximation Pattern 實做方式可能是多變的,但最終的目標都是透過計算約略正確的值來減少資源的消耗。


影片說明 (en)