خانه / NoSQL / بانکهای اطلاعاتی سطر گسترده / نگاهی به مدلسازی داده ها در کاساندرا
مدلسازی داده ها در کاساندرا

نگاهی به مدلسازی داده ها در کاساندرا

چند روز پیش یکی از خوانندگان سایت مهندسی داده، سوالی را در خصوص نحوه طراحی جداول برای یک کاربرد شبکه اجتماعی در کاساندرا مطرح کرد با این توضیحات که قرار است فهرست دنبال کنندگان یک کاربر را ذخیره کنیم . برای این منظور دو جدول در کاساندرا در نظر گرفته ایم : جدول followers و جدول followers_by_time با ساختار زیر :‌

1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE IF NOT EXISTS followers (
user_id uuid,
f_user_id uuid,
PRIMARY KEY ((user_id),f_user_id)
);

CREATE TABLE IF NOT EXISTS followers_by_time (
user_id uuid,
f_time TIMESTAMP,
f_user_id uuid,
PRIMARY KEY ((user_id),f_time,f_user_id)
) WITH CLUSTERING ORDER BY (f_time DESC, f_user_id DESC);

برای درج و جستجوی دنبال کنندگان و ترتیب زمانی آنها مشکلی نداریم اما اگر یک کاربر ، کاربر دیگری را آنفالو یا ترک کند، از جدول اول به راحتی حذف می شود اما از جدول دوم قابل حذف نیست .

قبل از اینکه پاسخ این سوال و راه حل پیشنهادی را مطرح کنم،‌ بهتر است نگاهی دقیق به نحوه مدلسازی داده ها در کاساندرا داشته باشیم .

انواع کلید در کاساندرا

مشابه بانکهای اطلاعاتی رابطه ای ، ما مفهوم کلید را هم در کاساندرا داریم اما این کلید چند تفاوت عمده با پدران خود دارد . اول اینکه ،‌ این کلید نحوه توزیع داده ها را در کلاستر و شبکه تعیین می کند ( بخش Partition Key) و دوم اینکه نحوه مرتب سازی داده ها هم درون یک سطر ، بر اساس این کلید خواهد بود ( بخش Cluster Key) . نکته سوم اینکه بازیابی و جستجوی اطلاعات در هر جدول بر اساس کلید ها و با لحاظ ترتیب آنها صورت می گیرد یعنی اگر برای یک جدول ما سه فیلد را به عنوان کلید تعیین کرده باشیم ، تنها به سه صورت می توانیم داده های آن جدول را جستجو کنیم : بر اساس کلید اول ، کلید اول و کلید دوم و نهایتاْ کلید اول و دوم و سوم .

تفاوت بعدی هم به ماهیت کلیدها بر میگردد که یک کلید در بانکهای اطلاعاتی رابطه ای، یک رکورد را در یک جدول به صورت منحصر بفرد مشخص می کنند اما بخاطر ماهیت ذخیره داده ها در کاساندرا که به ما امکان ایجاد یک سطر عریض با میلیاردها ستون را می دهد،‌ برای یافتن یک داده خاص ،‌ما نیاز داریم که هم سطر متناظر را در کاساندرا پیدا کنیم (Partition Key) و هم درون آن سطر،‌ ستون یا مجموعه ستون های مرتبط با هم (Column Family) که معادل یک رکورد اطلاعاتی هستند را بیابیم (Clustering Key) .

یک کلید (Primary Key) در کاساندرا یا ساده است و از یک بخش تشکیل شده است که در این صورت تمام فیلدهای کلید همان Partition Key‌ هستند و یا اگر از دو بخش تشکیل شود (جلوی پرانتز Primary Key بیش از یک داده داشته باشیم که با ویرگول از همدیگر جدا شده باشند ) یک کلید مرکب یا Composite Key‌ داریم که از  Partition Key‌ و Clustering Key تشکیل می شود . بخش اول کلید (اولین بخش از لیست فیلدهای کلید) را Partiton Key می گوییم و تمام فیلدهای بعدی جزء Clustering Key هستند.

به عنوان مثال در جدول زیر ما یک کلید مرکب داریم که بخش اول آن که کلید سطر ما نیز هست خود از دو قسمت تشکیل شده است (k_part_one,k_part_two) و تمام فیلدهای بعدی هم Clustering Key‌ آن سطر هستند و داده ها بر اساس آنها درون یک سطر هم مرتب می شوند و هم قابل جستجو خواهند بود .

1
2
3
4
5
6
7
8
9
CREATE TABLE stackoverflow (
k_part_one text,
k_part_two INT,
k_clust_one text,
k_clust_two INT,
k_clust_three uuid,
DATA text,
PRIMARY KEY((k_part_one,k_part_two), k_clust_one, k_clust_two, k_clust_three)
);

برای مشاهده مثال کامل، کلیک کنید.

نحوه مرتب سازی داده ها در کاساندرا

در کاساندرا ما مفهومی به اسم مرتب سازی نداریم همانطور که Join‌ و اتصال نداریم . در عوض، می توانیم هنگام طراحی یک جدول،‌به کاساندرا اعلام کنیم که درون یک سطر، داده ها به چه ترتیبی ذخیره شوند . این امر از طریق فیلدهای درون Clustering Key‌ صورت می گیرد و بعد از تعریف جدول با دستور With Clustering Order By صورت می پذیرد (اگر ذکر نشود به صورت پیش فرض براساس فیلد اول به صورت صعودی بعد بر اساس فیلد دوم به صورت صعودی و …. داده ها ذخیره خواهند شد) بنابراین در جدول followers_by_time ، عبارت

WITH CLUSTERING ORDER BY (f_time DESC, f_user_id DESC)

به این معناست که به ازای یک یوزر خاص (آی دی یوزر کلید سطر یا همان Partition Key است)‌ ، داده های این سطر بر اساس زمان به صورت نزولی و در صورت یکسان بودن زمان ، بر اساس شناسه کاربر دنبال کننده به صورت نزولی مرتب شود . یعنی با داشتن یک یوزر خاص، اگر ده رکورد اول این سطر را بخوانیم ،‌ آخرین کاربران دنبال کننده یک کاربر خاص را به ترتیب زمانی مشاهده خواهیم کرد.

اگر ما نیاز داریم که به ازای یک کاربر خاص،‌ دنبال کننده های او را مرتب شده بر اساس نام نمایش دهیم ، یک جدول دیگر نیاز خواهیم داشت که در آن ، Clustering Key ما با نام کاربر شروع شود و داده ها بر اساس نام، درون سطر به صورت مرتب شده، ذخیره شوند.

طراحی جداول بر اساس پرس و جو های مورد نیاز

نکته اصلی در طراحی جداول در کاساندرا ، این است  کلاْ مفاهیم بانکهای رابطه ای کلاسیک را کنار بگذارید و نگران افزونگی و تکرار اطلاعات نباشید و با توجه به اینکه بانک اطلاعاتی کاساندرا، پرس و جو محور است، برای هر پرس و جو، بک جدول طراحی کنید . (البته در نسخه ۳ با معرفی امکان نماهای ذخیره شده این مشکل و تعدد جداول تا حدودی برطرف شده است) . بنابراین اگر نیاز داریم که لیست شماره تلفن های یک سازمان  را هم براساس واحد اداری و هم بر اساس نام افراد داشته باشیم ،‌ باید یک جدول بگیریم برای مرتب سازی بر اساس واحد های اداری که کلید سطر می تواند نام ساختمان و کلید مرتب سازی واحد اداری باشد و در جدول دوم،‌ کلید سطر همان نام ساختمان و کلید مرتب سازی یا جستجو، نام افراد خواهد بود .

البته در این طراحی، با داشتن نام یک فرد، قادر به یافتن شماره تلفن فرد نخواهیم بود چون کلید اول جستجو نام ساختمان است و تا نام ساختمان را در پرس و جو نداشته باشیم، جستجو بر اساس فیلدهای بعدی امکان پذیر نیست  . بنابراین برای جستجو نام افراد ،‌مستقل از ساختمان و واحد اداری، یک جدول دیگر نیاز داریم که کلید آن، نام شخص خواهد بود .

این نوع از طراحی کاملاْ مغایر اصل کاهش افزونگی و نرمال سازی بانکهای اطلاعاتی رابطه ایست اما سرعت بسیار زیاد در پاسخگویی به سوالات و مقیاس پذیری بالای کاساندرا،‌ما را به این روش، دلگرم می کند.

راه حل پیشنهادی برای مشکل فوق

امیدوارم مشکل دوست عزیزمان را متوجه شده باشید. به دلیل نیاز به نمایش لیست دنبال کنندگان یک شخص بر اساس زمان، جدول followers_by_time طراحی شده است که کلید اول، آی دی شخص دنبال شونده و کلید دوم هم زمان (کلید سوم به نظرم ضرورتی نداشت) است تا بتوان داده ها را به ازای یک کاربر خاص،‌ مرتب شده نمایش داد. بنابراین طبق این طراحی، برای یافتن یک دنبال کننده خاص برای یک کاربر، اول باید شناسه کاربر اصلی و بعد زمان دنبال کردن را حتماْ داشته باشیم. جدول اول هم followers برای بررسی اینکه یک شخص، یک شخص دیگر را دنبال می کند یا نه در نظر گرفته شده است .

برای حل این مشکل که برای حذف یک کاربر از لیست دنبال کنندگان یک شخص، حتماْ زمان دنبال کردن را هم باید داشته باشیم، کافیست فیلد زمان را به جدول اول اضافه کنیم و زمانی که یک دنبال کننده، یک کاربر را ترک کرد، اول از جدول فوقانی با دادن شناسه دو کاربر، زمان را به دست آوریم و بعد در جدول پایین ، براساس نام کاربر و زمان، کاربر دنبال کننده را حذف می کنیم . بنابراین جداول نهایی بدینصورت خواهند بود :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE TABLE IF NOT EXISTS followers (
user_id uuid,
f_user_id uuid,

f_time TIMESTAMP,
PRIMARY KEY ((user_id),f_user_id)
);

CREATE TABLE IF NOT EXISTS followers_by_time (
user_id uuid,
f_time TIMESTAMP,
f_user_id uuid,
PRIMARY KEY ((user_id),f_time,f_user_id)
) WITH CLUSTERING ORDER BY (f_time DESC, f_user_id DESC);

البته می توان یک جدول اصلی مثلاْ Followers را طراحی کرد و بقیه گونه های ترتیبی این جدول را با نماهای ذخیره شده، پیاده سازی نمود.

سخن پایانی

اینکه بخواهیم یک ساختار کاملاْ رابطه ای را با کاساندرا مدل کنیم و همه چیز را در کاساندرا ذخیره کنیم، به نظر راه حل درستی به نظر نمی رسد و فقط برای داده هایی که به ازای یک کلید خاص، قرار است میلیون ها داده را ذخیره و با سرعت بالا جستجو کنیم مانند داده های سری زمانی به سراغ این بانک اطلاعاتی قدرتمند بیاییم . حتی امروزه می توان ساختار اصلی معماری بانک اطلاعاتی را بر اساس پستگرس بنا کرد و بعضی جداول خاص را پشت صحنه در کاساندرا ذخیره کرد
(قابلیت FDW) اما کاربر هنگام استفاده ، با پستگرس (یا ماریا دی بی که نسخه ای از MySQL است ) کار می کند و استفاده از کاساندرا، از دید کاربر و برنامه نویس پنهان است .

برای یادگیری عمیق تر مفاهیم مدلسازی داده ها با کاساندرا به این مقاله جامع و کامل سایت EBay حتما مراجعه کنید. ابزارهایی هم اخیراْ برای این منظور وارد بازار شده اند که البته جای طراحی انسانی را نخواهند گرفت .

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

Time limit is exhausted. Please reload CAPTCHA.