আমরা যারা সফটওয়্যার ইঞ্জিনিয়ার বা যারা টেকনোলোজি নিয়ে কাজ করি বা যে যাই নিয়ে আছি না কেন, সবাই আমরা একটা কথায় একমত হব যে, প্রতিটা টেকনোলজি কোন না কোন নির্দিষ্ট সমস্যাকে সমাধান করতে এসেছে, সেইটা প্রোগ্রামিং লেঙ্গুয়েজে থেকে শুরু করে ডাটাবেস, ফ্রেমেওয়ার্ক কিংবা লাইব্রেরি (প্রোগ্রামিং ল্যাঙ্গুয়েজে এর) পর্যন্ত, তা না হলে টেকনোলজির এত বিস্তার কখনোই হতো না।
Elasticsearch কি
এটি একটি NoSQL ডাটাবেস যেটা বিশেষ ভাবে distributed search এবং aggregation ইঞ্জিন হিসাবে ব্যবহার এর জন্য বানানো হয়েছে। Elasticsearch এ স্ট্রাকচার্ড এবং আনস্ট্রাকচার্ড ডাটা ইন্সার্ট করা যায় এবং তার ভিত্তিতে রেজাল্ট পাওয়া যায়। আমরা সবাই NoSQL ডাটাবেস হিসাবে MongoDB এর কথা জানি কিন্তু MongoDB সাধারণ ভাবে (general purpose) NoSQL কে ব্যবহার করার জন্য বানানো হয়েছে। Elasticsearch এর রেজাল্ট কিন্তু প্রায় রিয়েল টাইম।
কেন প্রয়োজন
আগে একটা কেইস বলি তারপর কেন প্রয়োজন সেইটা নিয়ে বলবো, কথা দিলাম। আমরা যখন একটা সফটওয়্যার বানায়, তখন আমাদের সফটওয়্যার খুব ভালো ভাবে চলে, আচরণ ও ভালো করে কিন্তু আস্তে আস্তে যখন সফটওয়্যার এর বয়স ও দায়িত্ব বাড়তে থাকে (ডাটা ভলিউম, read এবং write concurrency) তখন আর আগের মতো ভালো আচরণ করে না, স্লো হয়ে যায়, ল্যাটেন্সি বেড়ে যায়। ফলাফলে end user নাখোশ। এইটা হয় বেশিরভাগ সময় ঠিকঠাক ইনডেক্সিং না করা, রেপ্লিকেশনের অভাব, পচা কোয়েরি (N + ১) লেখা এবং সর্বোপরি না বুঝে ডাটাবেস সিলেক্ট করা (কোথায় কত ইঞ্চির পেরেক মারা লাগবে তা জানা জরুরি)।
তারপর খুব সাধারণ ভাবে প্রায় সময় আমরা দোষ দেয় প্রোগ্রামিং ল্যাঙ্গুয়েজকে, ভাবি, ইশ একটা রকেট মার্কা ল্যাংগুজে দিয়ে লিখলে আজ এই দিন দেখা লাগতো না। বেশির ভাগ সময় সময় সফটওয়্যার (ডাটা পারসিস্ট করে এমন) এর bottleneck থাকে হল ডাটাবেস
এইবার আসি মূল গল্পে, কেন প্রয়োজন,
- আপনি একটা ইকমার্স সফটওয়্যার বানাচ্ছেন যেইখানে হেভি সার্চ অপারেশন আছে, প্রোডাক্ট এর সংখ্যা ১০ লাখ বা তার ও বেশি। আপনাকে কিওয়ার্ড ধরে ধরে প্রথমে সাজেশন দেখতে হবে তারপর রেজাল্ট এবং ফিল্টার ও থাকতে পারে। রেস্পন্স টাইম থাকতে হবে ৩০০ মিলিসেকেন্ড এর কাছাকাছি।
- আপনি একটা রিয়েল এস্টেট সফটওয়্যার বানাচ্ছেন বাংলাদেশ এর জন্য যেইখানে geolocation এর উপর সার্চ হবে। ধরুন বনানী লিখে সার্চ দেয়ার পর বনানী এরিয়ার ভিতর এ যত বাসা ভাড়া দেয়া হবে তার একটা লিস্ট আসবে। মানে বনানীর পলিগন দিয়ে সার্চ।
- আপনার কাছে প্রচুর পরিমানে ডাটা আছে যেখানে ফুল টেক্সট সার্চ দরকার, উদহারণ হিসাবে ব্লগ টাইপের কনটেন্ট যেখানে সেন্টেন্স দিয়ে সার্চ করে কন্টেন্ট গুলা ফিল্টার করতে চাচ্ছেন
- আপনি দেশের জাতীয় ডাটাবেস থেকে একটা ডেমোগ্রাফিক aggregetion চাচ্ছেন, যেমন – বয়স, জেন্ডার, চাকরি, বেকার এর সংখ্যা ইত্যাদি এর রিপোর্ট। ডেটা ভলিউম বুজতেই পারছেন, প্রায় ১৮ কোটি এর উপর
আমি শুধু কিছু আইডিয়া দেয়ার চেষ্টা করলাম কেইস গুলা বলে, এছাড়া আরো অনেক কিছু থাকতে পারে, এইটা আপনাদের বিবেচনা।
কিছু মৌলিক জ্ঞান
Elasticsearch এর কথা যখনি বলছি তখন অনেকে হয়তো SQL এর সাথে তুলুনা করতে পারেন। বুঝার সুবিধার্তে SQL এর সাথে তুলুনা করলে Elasticsearch এর কোনটাকে আমরা কি বলতে পারি এবং কি কি পার্থক্য আছে, সেইগুলা নিয়ে কথা হবে।
চলুন শুরু করি –
SQL | Elasticsearch | পার্থক্য |
column | field | SQL এ field এর যে data type দিব, আমাদেরকে সেইটাই ব্যবহার করতে হবে কিন্তু elasticsearch এ আমরা একই datatype এর একাধিক (list) data রাখতে পারি |
row | document | SQL এর row বেশ কড়া (strict), schema তে যা আছে তাতেই ডাটা ঢুকাতে হবে, যতটা আছে, ঠিক ততটা কিন্তু elasticsearch এই দিক দিয়ে ফ্লেক্সিবল (যদিও তার schema আগে বলে দেয়া যায়), রানটাইমে column ও বাড়ানো যায় |
table | index | দুইটায় একই জিনিস, মানে যার উপর query হবে |
schema | implicit | SQL এ schema হল একটা boundary (দুস্টুমি চলবে না), elasticsearch schemaless হলেও predefined mapping করা যায় (বিস্তারিত পরে বলবো) যদিও পরবর্তীতে field এর সংখ্যা runtime এ বাড়ানো যায় |
database | cluster | SQL এ অনেক গুলা table একটা database এ encapsulate থাকে, elasticsearch এ database কন্সেপ্টটা নাই কিন্তু এইখানে indices গুলা একটা cluster এর মধ্যে থাকে। মানে, এইখানে SQL এর মতো আলাদা database তৈরি করা যায় না। |
Mapping
Elasticsearch এ mapping হলো, index (table) এর মধ্যে field গুলাকে কিভাবে রাখা হবে / store হবে, কিভাবে index হবে তার একটা process. সহজ কথা হলো – একটা schema define করে দেয়া কোন field এর data type কেমন হবে এবং indexable হবে কিনা। যেমন – name, email, age, gender তিনটা ফিল্ড আছে
PUT /users { "mappings": { "properties": { "name": { "type": "text" } "email": { "type": "keyword" }, "age": { "type": "integer" }, "gender": { "type": "keyword", "index": false, }, } } }
তারপর যখন data ঢুকানো হবে তখন mapping অনুযায়ী data persist হবে। elasticsearch এ by default সব কিছু index থাকে, যদি কোন ফিল্ড এর index দরকার না হয় তখন mapping এর সময় index কে false করে দেয়া যায়।
Mapping দুই ধরণের হতে পারে
- Dynamic mapping
- যদি field এর নাম এবং data type যদি run time এ সেট হয়, predefined না থাকে তাহলে dynamic mapping ভালো একটা চয়েজ
- Explicit mapping
- এই mapping টাতে অনেক বেশি কন্ট্রোল পাওয়া যায়, যেহেতু predefined থাকে field এর নাম এবং data type
Field এর data type
কিছু কমন data type নিয়ে কথা বলবো, যেগুলা প্রায় সব সময় লাগে
- text – যখন একটা বড় content রাখতে হয় এবং পরে full text search করার প্রয়োজন হয়, তখন এটি ব্যবহার করা হয় সাধারণত
- keyword – exact match করবে এই ধরণের কেইস এ keyword ব্যবহার করা হয়
- numeric – এইখানে integer, long, short, double, float এবং আরো কিছু ধরণের value রাখা যায়
- date – এইখানে বিভিন্ন format এ date রাখা যায় – date, date-time, milliseconds-since-the-epoch ইত্যাদি
- boolean – true, “true”, false, “false”
- object – field এ inner object হিসাবে data রাখার জন্য
- geo_point – এই field এ latitude এবং longitude রাখা যায়
- একটা boundary এর ভিতরে geopoint খুঁজে পাওয়ার জন্য
- central point থেকে নির্দিষ্ট দুরুত্বে (radius এ) অন্য coordinate গুলা খুঁজে বের করার জন্য
- polygon দিয়ে search করার জন্য
- geographically কোন aggregated data পাওয়ার জন্য
- distance এর ভিত্তিতে sort করার জন্য
- multipolygon দিয়ে search করে data পাওয়ার জন্য
- geo_shape – যে কোন latitude এবং longitude এর shape store করার জন্য এটি ব্যবহার করা যায়, যেমন – polygon, multipolygon অথবা যে কোন ধরণের shape, যা দিয়ে পরবর্তীতে geo_point এর উপর search operation চালিয়ে data পাওয়া যায়
আরো অনেক ধরনের data type আছে, দয়া করে নিজ দায়িত্বে দেখে নিবেন elasticsearch documentation এ
DSL query
DSL (Domain specific language) হল JSON based query language. DSL query দুইটা context এর উপর রান করে – query, filter
- Query context: এই context টার মূল লক্ষ্য হল, একটা query এর response কতটা match করবে এবং relevant হবে। document এ _score নামে একটা meta field থাকে, যেখানে একটা number থাকে, যেই document এর _score যত বেশি সেইটা ততটা match করেছে এবং সেইটা সবচেয়ে relevant
- Filter context: এই context মূলত কোন কিছু filter করে আনার জন্য, match করতে ও পারে আবার না ও পারে। এই context এর কোন _score নেই এবং এটি ব্যবহার করা হয় structure data filter করার জন্য। filter context frequent call হলে, elasticsearch তা cache করে রাখে performance বাড়ানোর জন্য।
Query এবং filter context এর একটি উদাহরণ –
- title ফিল্ড এ Database নামের একটা word (text data type) থাকবে
- content field এ Elasticsearch নামের একটা word (text data type) থাকবে
- status field এ published নামের একটা exact word (keyword data type) থাকবে
- published_date এ একটা date (date data type) থাকবে
GET posts/_search { "query": { "bool": { "must": [ { "match": { "title": "Database" }}, { "match": { "content": "Elasticsearch" }} ], "filter": [ { "term": { "status": "published" }}, { "range": { "publish_date": { "gte": "2015-01-01" }}} ] } } }
- এইখানে query parameter টা query context কে বুজাচ্ছে
- bool এবং match ব্যবহার করা হচ্ছে query context এ যাতে কতটা ভালো ভাবে match হয়েছে তার উপর ভিত্তি করে _score আসে
- filter parameter দিয়ে filter context বুঝানো হচ্ছে, term এবং range query দিয়ে docuent filter করে আনা হচ্ছে, এতে query context এর _score এর কোন সমস্যা হবে না।
Compound queries
এক বা একাধিক leaf queries অথবা compound query এর সমন্বয়ে compound query তৈরী হয়। সহজ ভাষায় বলতে গেলে bool, boosting অথবা এই ধরণের আরো কিছু scope এ যখন কোন query কে group করা হয়।
- Bool – document গুলা query তে match করে আসবে কি আসবে না তার একটা boolean combination. bool এর ভিতর must, must_not, should, filter ব্যবহার করা হয়
- must – যেই clause গুলা match করতেই হবে, সেইগুলা must দিয়ে ব্যবহার করা যায়
- must_not – যেই clause গুলা ম্যাচ করবে না, সেইগুলা must_not এ রাখা হয়
- should – যখন কোন additional value দিয়ে match এর relevency বাড়িয়ে _score বাড়ানো হয় তখন should ব্যবহার করা হয়
Match query
যখন word / sentence দিয়ে কোন content search করার প্রয়োজন হয় তখন match query দিয়ে full text search করা যায়। field এর data type text হতে হবে
GET posts/_search { "query": { "match": { "body": { "query": "elasticsearch is fast" } } } }
Match query বিভিন্ন ভাবে করা যায়, documentation বিস্তারিত বলা আছে, আমি শুধু প্রাথমিক ধারণা দিয়েছি
Term query
যখন exact match প্রয়োজন হয় তখন term query করা হয়, এই ক্ষেত্রে field এর data type keyword হতে হবে
GET posts/_search { "query": { "match": { "body": { "query": "elasticsearch is fast" } }, "term": { "is_published": { "value": true } } } }
Range query
যখন কোন range এর ভিতরে search করার প্রয়োজন হয় তখন এই query ব্যবহার করা যায়, যেমন – numeric value অথবা date এর range
GET populations/_search { "query": { "range": { "age": { "gte": 10, "lte": 20 } } } }
Geo distance query
কোন geo_point থেকে নির্দিষ্ট radius এ geolocation based search করার জন্য এই query ব্যবহার করা হয়ে থাকে।
GET /locations/_search { "query": { "bool": { "must": { "match_all": {} }, "filter": { "geo_distance": { "distance": "20km", "pin.location": { "lat": 40, "lon": -70 } } } } } }
Geo shape query
কোন geo_point এর উপর polygon অথবা multipolygon দিয়ে search করে documents পাওয়ার জন্য geo_shape কোয়েরি করা হয়। ধরা যাক, বনানী এলাকার ভিতরে সব হসপিটাল এর documents লাগবে (হসপিটাল এর geo_point গুলা আগে থেকে ingest করা আছে), তখন বনানী এলাকার multipolygon দিয়ে search করলে সব গুলা documents পাওয়া সম্ভব।
GET /hospitals/_search { "query": { "bool": { "must": { "match_all": {} }, "filter": { "geo_shape": { "location": { "shape": { "type": "multipolygon", "coordinates": [ [ 13.0, 53.0 ], [ 14.0, 52.0 ] ] } } } } } } }
শেষের কথা
আমি চেষ্টা করেছি সহজ ভাবে বলার এবং শক্ত কথা গুলা এড়িয়ে যাওয়ার, elasticsearch বেশ বড় একটা বিষয়, এর মধ্যে আরো অনেক কিছু আছে, আমি শুধু কিছু প্রাথমিক আলোচনা করার চেষ্টা করেছি। আমার আলোচনার বাহিরে আরো অনেক বিষয় আছে যেমন – aggregation (মেট্রিক্স দেখানোর জন্য অনেক কাজের একটা জিনিস), kibana (data visualization এর জন্য), logstash (data migration এর কাজে লাগে) এবং আরো অনেক কিছু, যা নিয়ে আলোচনা করা হয় নাই। নিজ গুনে দেখে নেয়ার জন্য অনুরুধ করা হলো।