Nevados এ সফ্টওয়্যার দলের অংশ হিসাবে আমরা Nevados All Terrain Tracker® এর জন্য একটি অপারেশন এবং পর্যবেক্ষণ প্ল্যাটফর্ম তৈরি করছি। একটি সৌর ট্র্যাকার একটি যন্ত্র যা সূর্যের দিকে একটি সৌর প্যানেলকে নির্দেশ করে। প্রতিটি সোলার ট্র্যাকার ক্রমাগত আমাদের প্ল্যাটফর্মে বর্তমান কোণ, তাপমাত্রা, ভোল্টেজ ইত্যাদির মতো অবস্থার তথ্য এবং রিডিং পাঠায় এবং আমাদের বিশ্লেষণ এবং ভিজ্যুয়ালাইজেশনের জন্য এই তথ্য সংরক্ষণ করতে হবে। যদি ট্র্যাকারটি প্রতি 5 সেকেন্ডে ডেটা পাঠানোর জন্য কনফিগার করা হয়, তাহলে আমাদের কাছে প্রতিদিন ট্র্যাকার প্রতি 17,280 ডেটা পয়েন্ট, প্রতি মাসে ট্র্যাকার প্রতি 518,400 ডেটা পয়েন্ট রয়েছে। যে অনেক তথ্য যোগফল. এই ধরণের ডেটাকে "টাইম-সিরিজ ডেটা" বলা হয় এবং সফ্টওয়্যারের সমস্ত জটিল সমস্যার জন্য এটির জন্য বেশ কয়েকটি সমাধান (টাইম সিরিজ ডেটাবেস) রয়েছে। সবচেয়ে বিখ্যাত হল InfluxDB এবং TimescaleDB। আমাদের প্ল্যাটফর্মের জন্য, আমরা TDEngine-এর সাথে কাজ করার সিদ্ধান্ত নিয়েছি, একটি অপেক্ষাকৃত নতুন পণ্য যা IoT অ্যাপ্লিকেশনের জন্য অপ্টিমাইজ করা হয়েছে এবং SQL কোয়েরি ভাষার সাথে কাজ করে।
এই সিদ্ধান্তের জন্য বিভিন্ন যুক্তি ছিল: TDEngine
এই নিবন্ধে, আমরা একটি TDEngine ডাটাবেস এবং টেবিলের সেটআপের মধ্য দিয়ে যাব এবং কীভাবে একটি GraphQL স্কিমা তৈরি করতে হয় যা আমাদের বিভিন্ন ক্লায়েন্ট এবং অ্যাপ্লিকেশন থেকে ডেটা অনুসন্ধান করতে দেয়।
TDEngine দিয়ে শুরু করার সবচেয়ে সহজ উপায় হল তাদের ক্লাউড পরিষেবা ব্যবহার করা। TDEngine এ যান এবং একটি অ্যাকাউন্ট তৈরি করুন। তাদের কাছে কিছু পাবলিক ডাটাবেস রয়েছে যা আমরা ব্যবহার করতে পারি, যা একটি ডেমো বা প্রশ্নের সাথে পরীক্ষা করার জন্য দুর্দান্ত।
আপনি যদি স্থানীয়ভাবে TDEngine চালাতে চান, আপনি ডকার ইমেজ এবং টেলিগ্রাফ ব্যবহার করতে পারেন বিভিন্ন উত্স থেকে ডেটা পুনরুদ্ধার করতে এবং ডেটাবেসে পাঠাতে, যেমন সিস্টেম তথ্য, পিং পরিসংখ্যান ইত্যাদি।
version: '3.9' services: tdengine: restart: always image: tdengine/tdengine:latest hostname: tdengine container_name: tdengine ports: - 6030:6030 - 6041:6041 - 6043-6049:6043-6049 - 6043-6049:6043-6049/udp volumes: - data:/var/lib/taos telegraf: image: telegraf:latest links: - tdengine env_file: .env volumes: - ./telegraf.conf:/etc/telegraf/telegraf.conf
Telegraf কনফিগারেশনের জন্য অফিসিয়াল ডকুমেন্টেশন এবং Telegraf এ TDEngine ডকুমেন্টেশন দেখুন। সংক্ষেপে, এটি একটি MQTT বিষয়ের সাথে সংযোগ করতে এইরকম কিছু দেখাবে:
[agent] interval = "5s" round_interval = true omit_hostname = true [[processors.printer]] [[outputs.http]] url = "http://127.0.0.1:6041/influxdb/v1/write?db=telegraf" method = "POST" timeout = "5s" username = "root" password = "taosdata" data_format = "influx" [[inputs.mqtt_consumer]] topics = [ "devices/+/trackers", ]
স্থানীয়ভাবে সবকিছু সেট আপ করার পরিবর্তে এবং ডেটাবেস তথ্য পূরণের জন্য অপেক্ষা করার পরিবর্তে, আমরা এই নিবন্ধটির জন্য সর্বজনীন ডাটাবেস ব্যবহার করব, যা 5টি প্রধান মার্কিন বন্দর থেকে জাহাজ চলাচল ধারণ করে।
ডিফল্টরূপে, TDEngine-এর টেবিলে একটি অন্তর্নিহিত স্কিমা থাকে, যার অর্থ স্কিমা ডাটাবেসে লেখা ডেটার সাথে খাপ খায়। এটি বুটস্ট্র্যাপিংয়ের জন্য দুর্দান্ত, কিন্তু অবশেষে, আমরা ইনকামিং ডেটার সমস্যাগুলি এড়াতে একটি স্পষ্ট স্কিমাতে স্যুইচ করতে চাই। একটি জিনিস যা অভ্যস্ত হতে একটু সময় নেয় তা হল তাদের সুপার টেবিলের ধারণা (সংক্ষেপে "স্থিতিশীল")। TDEngine এ ট্যাগ (কী) এবং কলাম (ডেটা) আছে। প্রতিটি কী সমন্বয়ের জন্য, একটি "টেবিল" তৈরি করা হয়। সমস্ত টেবিল STable গ্রুপ করা হয়.
vessel
ডাটাবেসের দিকে তাকালে, তাদের ais_data
নামে একটি STable আছে যাতে অনেকগুলি টেবিল রয়েছে। সাধারণত, আমরা প্রতি-টেবিলের ভিত্তিতে প্রশ্ন করতে চাই না, তবে সব টেবিল থেকে জমে থাকা ডেটা পেতে সর্বদা STable ব্যবহার করি।
TDEngine এর DESCRIBE
একটি ফাংশন রয়েছে যা আমাদের একটি টেবিল বা স্থিতিশীলতার স্কিমা পরিদর্শন করতে দেয়। ais_data
এর নিম্নলিখিত স্কিমা রয়েছে:
স্ট্যাবলে দুটি কী এবং ছয়টি ডেটা কলাম রয়েছে। চাবিগুলি হল mmsi
এবং name
। ডেটা জিজ্ঞাসা করতে আমরা নিয়মিত SQL স্টেটমেন্ট ব্যবহার করতে পারি:
SELECT ts, name, latitude, longitude FROM vessel.ais_data LIMIT 100; ts name latitude longitude 2023-08-11T22:07:02.419Z GERONIMO 37.921673 -122.40928 2023-08-11T22:21:48.985Z GERONIMO 37.921688 -122.40926 2023-08-11T22:25:08.784Z GERONIMO 37.92169 -122.40926 ...
মনে রাখবেন যে টাইম-সিরিজ ডেটা সাধারণত খুব বড় হয়, তাই আমাদের সর্বদা ফলাফল সীমিত করা উচিত। কিছু টাইম-সিরিজ নির্দিষ্ট ফাংশন আছে যেগুলো আমরা ব্যবহার করতে পারি, যেমন PARTITION BY
যা কী দ্বারা গোষ্ঠীভুক্ত হয় এবং সর্বশেষ আপডেট পৃথক কী পেতে উপযোগী। উদাহরণ স্বরূপ:
SELECT last_row(ts, name, latitude, longitude) FROM vessel.ais_data PARTITION BY name; ts name latitude longitude 2023-09-08T13:09:34.951Z SAN SABA 29.375961 -94.86894 2023-09-07T18:05:01.230Z SELENA 33.678585 -118.1954 2023-09-01T17:23:24.145Z SOME TUESDAY 33.676563 -118.230606 ...
আমি আরও উদাহরণের জন্য তাদের SQL ডকুমেন্টেশন পড়ার পরামর্শ দিই। আমরা এগিয়ে যাওয়ার আগে, "প্রোগ্রামিং", "Node.js" এ যান এবং আপনার TDENGINE_CLOUD_URL
এবং TDENGINE_CLOUD_TOKEN
ভেরিয়েবল পুনরুদ্ধার করুন৷
গ্রাফকিউএল আজকাল বেশ পরিচিত এবং এটি সম্পর্কে প্রচুর ভাল নিবন্ধ রয়েছে। আমরা বিভিন্ন উত্স থেকে তথ্য সংগ্রহ এবং প্রক্রিয়া করার জন্য প্রযুক্তিটি বেছে নিয়েছি এবং GraphQL আমাদেরকে স্বচ্ছভাবে একটি একক API এ একত্রিত করতে দেয়।
আমরা আশ্চর্যজনক Fastify ফ্রেমওয়ার্ক (এখন পর্যন্ত Node.js অ্যাপ্লিকেশনের জন্য ডিফল্ট পছন্দ) এবং Mercurius অ্যাডাপ্টার ব্যবহার করব। Mercurius এবং Fastify-এর দলগুলি একটি নির্বিঘ্ন অভিজ্ঞতার জন্য একসাথে কাজ করেছে এবং এটি পারফরম্যান্সের উপর ফোকাস সহ একটি দুর্দান্ত পছন্দ গ্রাফকিউএল API। গ্রাফকিউএল নেক্সাস হল স্কিমা এবং রিসোলভার তৈরি/জেনারেট করার একটি টুল, তাই আমাদের হাতে সবকিছু লিখতে হবে না।
কিছু সেটআপ কোড ইত্যাদি করতে হবে, যা আমি এখানে এড়িয়ে যাব। আপনি GitHub - tdengine-graphql-example- এ একটি সম্পূর্ণ উদাহরণ খুঁজে পেতে পারেন।
আমি এই নিবন্ধে দুটি বিষয় বিস্তারিত করতে চাই যা বরং নির্দিষ্ট:
TDEngine এর একটি Node.js লাইব্রেরি রয়েছে যা আমাদের ডাটাবেস অনুসন্ধান করতে দেয়। এটি সংযোগ করা এবং প্রশ্ন পাঠাতে সহজ করে তোলে, দুর্ভাগ্যবশত প্রতিক্রিয়াগুলির সাথে কাজ করা একটু কঠিন। তাই আমরা একটি ছোট মোড়ক লিখেছি:
'use strict' import tdengine from '@tdengine/rest' import { tdEngineToken, tdEngineUrl } from '../config.js' import parseFields from 'graphql-parse-fields' const { options: tdOptions, connect: tdConnect } = tdengine tdOptions.query = { token: tdEngineToken } tdOptions.url = tdEngineUrl export default function TdEngine(log) { this.log = log const conn = tdConnect(tdOptions) this.cursor = conn.cursor() } TdEngine.prototype.fetchData = async function fetchData(sql) { this.log.debug('fetchData()') this.log.debug(sql) const result = await this.cursor.query(sql) const data = result.getData() const errorCode = result.getErrCode() const columns = result.getMeta() if (errorCode !== 0) { this.log.error(`fetchData() error: ${result.getErrStr()}`) throw new Error(result.getErrStr()) } return data.map((r) => { const res = {} r.forEach((c, idx) => { const columnName = columns[idx].columnName .replace(/`/g, '') .replace('last_row(', '') .replace(')', '') if (c !== null) { res[columnName] = c } }) return res }) }
এটি একটি TDEngine অবজেক্ট প্রদান করে যা GraphQL প্রসঙ্গে পাস করা যেতে পারে। আমরা প্রাথমিকভাবে fetchData
ফাংশন ব্যবহার করব যেখানে আমরা একটি এসকিউএল কোয়েরিতে পাস করতে পারি এবং ফলাফলগুলিকে বস্তুর অ্যারে হিসাবে ফিরে পেতে পারি। TDEngine আলাদাভাবে মেটাডেটা (কলাম), ত্রুটি এবং ডেটা প্রদান করে। আমরা বস্তুর একটি নিয়মিত তালিকায় কলাম ম্যাপ করতে মেটাডেটা ব্যবহার করব। এখানে একটি বিশেষ কেস হল last_row
ফাংশন। কলামগুলি last_row(ts)
, last_row(name)
ইত্যাদি হিসাবে ফেরত দেওয়া হয় এবং আমরা last_row
অংশটি মুছে ফেলতে চাই যাতে বৈশিষ্ট্যটি গ্রাফকিউএল স্কিমার সাথে 1:1 মানচিত্র করে। এটি columnName.replace
অংশে করা হয়।
দুর্ভাগ্যবশত TDEngine-এর জন্য Postgraphile- এর মতো কোনও স্কিমা জেনারেটর নেই এবং আমরা একটি বিশুদ্ধ GraphQL স্কিমা লিখতে এবং বজায় রাখতে চাই না, তাই আমরা এটিতে আমাদের সাহায্য করার জন্য Nexus.js ব্যবহার করব। আমরা দুটি মৌলিক প্রকার দিয়ে শুরু করব: VesselMovement
এবং Timestamp
(যা একটি স্কেলার টাইপ)। Timestamp
এবং TDDate
দুটি ভিন্ন প্রকার যা তারিখটিকে একটি টাইমস্ট্যাম্প হিসাবে বা একটি তারিখ স্ট্রিং হিসাবে প্রদর্শন করার জন্য। এটি ক্লায়েন্ট অ্যাপ্লিকেশনের জন্য দরকারী (এবং বিকাশের সময়), কারণ এটি কোন বিন্যাসটি ব্যবহার করবে তা নির্ধারণ করতে পারে। asNexusMethod
আমাদের VesselMovement
স্কিমাতে একটি ফাংশন হিসাবে টাইপ ব্যবহার করতে দেয়। মূল ts
টাইমস্ট্যাম্প মান ব্যবহার করার জন্য আমরা এখানে টাইপ সংজ্ঞায় TDDate
সমাধান করতে পারি।
import { scalarType, objectType } from 'nexus' export const Timestamp = scalarType({ name: 'Timestamp', asNexusMethod: 'ts', description: 'TDEngine Timestamp', serialize(value) { return new Date(value).getTime() } }) export const TDDate = scalarType({ name: 'TDDate', asNexusMethod: 'tdDate', description: 'TDEngine Timestamp as Date', serialize(value) { return new Date(value).toJSON() } }) export const VesselMovement = objectType({ name: 'VesselMovement', definition(t) { t.ts('ts') t.tdDate('date', { resolve: (root) => root.ts }) t.string('mmsi') t.string('name') t.float('latitude') t.float('longitude') t.float('speed') t.float('heading') t.int('nav_status') } })
টাইম-সিরিজের জন্য, আমরা ইন্টারফেসে রিলেশনাল এবং টাইম-সিরিজ ধরনের স্পষ্ট বিভাজনের জন্য Movement
বা Series
প্রত্যয় ব্যবহার করি।
এখন আমরা কোয়েরি সংজ্ঞায়িত করতে পারি। TDEngine থেকে সর্বশেষ গতিবিধি পেতে আমরা একটি সহজ প্রশ্ন দিয়ে শুরু করব:
import { objectType } from 'nexus' export const GenericQueries = objectType({ name: 'Query', definition(t) { t.list.field('latestMovements', { type: 'VesselMovement', resolve: async (root, args, { tdEngine }, info) => { const fields = filterFields(info) return tdEngine.fetchData( `select last_row(${fields}) from vessel.ais_data partition by mmsi;` ) } }) } })
গ্রাফিকিউএল API পরীক্ষা করার এবং স্কিমা অন্বেষণ করার জন্য একটি দুর্দান্ত সরঞ্জাম, আপনি Mercurius-এ graphiql.enabled = true
পাস করে এটি সক্ষম করতে পারেন। প্রশ্নের সাথে, আমরা mmsi
দ্বারা গোষ্ঠীবদ্ধ জাহাজের সর্বশেষ গতিবিধি দেখতে পারি। চলুন একটু এগিয়ে যাই যদিও. GraphQL এর সবচেয়ে বড় সুবিধা হল ক্লায়েন্ট বা অ্যাপ্লিকেশনের জন্য একটি স্বচ্ছ স্তর। আমরা একাধিক উত্স থেকে ডেটা আনতে পারি এবং সেগুলিকে একই স্কিমাতে একত্রিত করতে পারি।
দুর্ভাগ্যবশত, আমি বিস্তৃত জাহাজের তথ্য সহ একটি সহজ/ফ্রি API খুঁজে পাইনি। সেখানে Sinay আছে, কিন্তু তারা তাদের ভেসেল রেসপন্সে শুধুমাত্র name
, mmsi
এবং imo
প্রদান করে (যা আমাদের ইতিমধ্যেই TDEngine এ আছে)। উদাহরণের খাতিরে, আমরা ধরে নিই যে আমাদের ডাটাবেসে name
নেই এবং আমাদের সিনে থেকে এটি পুনরুদ্ধার করতে হবে। imo
এর সাহায্যে আমরা একটি জাহাজের জন্য CO2 নির্গমনের প্রশ্নও করতে পারি বা অন্য API একটি চিত্র, পতাকা বা অন্যান্য তথ্য পুনরুদ্ধার করতে ব্যবহার করা যেতে পারে, যার সবকটিই Vessel
প্রকারে একত্রিত করা যেতে পারে।
export const Vessel = objectType({ name: 'Vessel', definition(t) { t.string('mmsi') t.string('name') t.nullable.string('imo') t.list.field('movements', { type: 'VesselMovement' }) } })
আপনি এখানে দেখতে পাচ্ছেন, আমরা TDEngine থেকে টাইম-সিরিজ ডেটা সহ একটি তালিকা ক্ষেত্রের movements
অন্তর্ভুক্ত করতে পারি। আমরা জাহাজের তথ্য আনার জন্য আরেকটি প্রশ্ন যোগ করব এবং সমাধানকারী আমাদের TDEngine এবং Sinay থেকে ডেটা একত্রিত করার অনুমতি দেয়:
t.field('vessel', { type: 'Vessel', args: { mmsi: 'String' }, resolve: async (root, args, { tdEngine }, info) => { const waiting = [ getVesselInformation(args.mmsi), tdEngine.fetchData( `select * from vessel.ais_data where mmsi = '${args.mmsi}' order by ts desc limit 10;` ) ] const results = await Promise.all(waiting) return { ...results[0][0], movements: results[1] } } })
🎉 এবং এখানে আমাদের কাছে অনুরোধ করা একটি নির্দিষ্ট জাহাজের জন্য TDEngine থেকে একটি কর্মরত GraphQL API রিটার্নিং সারি রয়েছে। getVesselInformation()
সিনে থেকে ডেটা আনার জন্য একটি সাধারণ মোড়ক। আমরা movements
অ্যাট্রিবিউটে TDEngine ফলাফল যোগ করব এবং GraphQL বাকিগুলোর যত্ন নেবে এবং স্কিমাতে সবকিছু ম্যাপ করবে।
যেকোনো এসকিউএল ডাটাবেসের মতো, ব্যবহারকারীর ইনপুট নিয়ে আমাদের সতর্ক থাকতে হবে। উপরের উদাহরণে আমরা সরাসরি mmsi
ইনপুট ব্যবহার করি, যা এই ক্যোয়ারীটিকে SQL ইনজেকশনের জন্য দুর্বল করে তোলে। উদাহরণের খাতিরে, আমরা আপাতত এটিকে উপেক্ষা করব, কিন্তু "বাস্তব বিশ্বের" অ্যাপ্লিকেশনগুলিতে, আমাদের সর্বদা ব্যবহারকারীর ইনপুট স্যানিটাইজ করা উচিত। স্ট্রিংগুলিকে জীবাণুমুক্ত করার জন্য চারপাশে বেশ কয়েকটি ছোট লাইব্রেরি রয়েছে, বেশিরভাগ ক্ষেত্রে আমরা শুধুমাত্র সংখ্যার উপর নির্ভর করি (পৃষ্ঠা, সীমা ইত্যাদি) এবং enums (সর্ট অর্ডার), যা GraphQL আমাদের জন্য পরীক্ষা করে।
এটি নির্দেশ করার জন্য দিমিত্রি জায়েটসকে ধন্যবাদ!
এই নিবন্ধের সুযোগের বাইরে কয়েকটি জিনিস রয়েছে, তবে আমি সেগুলি সংক্ষেপে উল্লেখ করতে চাই:
যখন আমরা প্রজেক্ট শুরু করি, তখন Nexus.js ছিল আমাদের GraphQL স্কিমা তৈরি করার সেরা পছন্দ। যদিও স্থিতিশীল এবং কিছুটা বৈশিষ্ট্য-সম্পূর্ণ , এতে রক্ষণাবেক্ষণ এবং আপডেটের অভাব রয়েছে। পোথোস নামে একটি প্লাগইন-ভিত্তিক গ্রাফকিউএল স্কিমা নির্মাতা রয়েছে যা একটু বেশি আধুনিক এবং সক্রিয়ভাবে রক্ষণাবেক্ষণ করা হয়। আপনি যদি একটি নতুন প্রকল্প শুরু করেন, আমি সম্ভবত Nexus.js এর পরিবর্তে Pothos ব্যবহার করার পরামর্শ দিচ্ছি।
এটি নির্দেশ করার জন্য মো স্যাটলারকে ধন্যবাদ!
আপনি উপরের Vessel
রিসোলভারে দেখতে পাচ্ছেন, উভয় ডেটা উত্স অবিলম্বে আনা এবং প্রক্রিয়া করা হয়। এর মানে যদি ক্যোয়ারীটি শুধুমাত্র name
জন্য হয়, আমরা এখনও প্রতিক্রিয়ার জন্য movements
আনতে পারি। এবং যদি ক্যোয়ারী শুধুমাত্র movements
জন্য হয়, আমরা এখনও সিনাই থেকে নাম আনছি এবং অনুরোধের জন্য সম্ভাব্য অর্থ প্রদান করি।
এটি একটি গ্রাফকিউএল অ্যান্টি-প্যাটার্ন এবং আমরা শুধুমাত্র অনুরোধ করা ডেটা আনার জন্য ক্ষেত্রের তথ্য ব্যবহার করে কর্মক্ষমতা উন্নত করতে পারি। সমাধানকারীদের চতুর্থ যুক্তি হিসাবে ক্ষেত্রের তথ্য রয়েছে, তবে তাদের সাথে কাজ করা বেশ কঠিন। পরিবর্তে, আমরা অনুরোধ করা ক্ষেত্রগুলির একটি সাধারণ বস্তু পেতে এবং সমাধানকারী যুক্তি সামঞ্জস্য করতে graphql-parse-fields
ব্যবহার করতে পারি।
আমাদের উদাহরণের প্রশ্নে, আমরা ডাটাবেস থেকে সমস্ত কলাম আনার জন্য select *
ব্যবহার করি এমনকি তাদের প্রয়োজন না হলেও। এটি স্পষ্টতই বেশ খারাপ এবং আমরা sql প্রশ্নগুলি অপ্টিমাইজ করতে একই ক্ষেত্র পার্সার ব্যবহার করতে পারি:
export function filterFields(info, context) { const invalidFields = ['__typename', 'date'] const parsedFields = parseFields(info) const fields = context ? parsedFields[context] : parsedFields const filteredFields = Object.keys(fields).filter( (f) => !invalidFields.includes(f) ) return filteredFields.join(',') }
এই ফাংশনটি GraphQL তথ্য থেকে ক্ষেত্রগুলির একটি কমা দ্বারা পৃথক করা তালিকা প্রদান করে।
const fields = filterFields(info) return tdEngine.fetchData( `select last_row(${fields}) from vessel.ais_data partition by mmsi;` )
যদি আমরা ts
, latitude
এবং longitude
জন্য অনুরোধ করি, প্রশ্নটি এইরকম দেখাবে:
select last_row(ts, latitude, longitude) from vessel.ais_data partition by mmsi;
এই টেবিলে শুধুমাত্র কয়েকটি কলামের সাথে এটি খুব বেশি গুরুত্বপূর্ণ নাও হতে পারে, তবে আরও টেবিল এবং জটিল প্রশ্নের সাথে, এটি অ্যাপ্লিকেশন কর্মক্ষমতাতে বিশাল পার্থক্য আনতে পারে।
TDEngine-এর কিছু সময়-সিরিজ নির্দিষ্ট এক্সটেনশন রয়েছে যা কর্মক্ষমতা উন্নত করতে ব্যবহার করা উচিত। উদাহরণস্বরূপ, সর্বশেষ এন্ট্রি পুনরুদ্ধার করতে, একটি ঐতিহ্যগত SQL ক্যোয়ারী:
SELECT ts, name, latitude, longitude FROM vessel.ais_data order by ts desc limit 1;
চালানোর জন্য 653ms লাগে, যখন "TDEngine" ক্যোয়ারী মাত্র 145ms লাগে:
SELECT last_row(ts, name, latitude, longitude) FROM vessel.ais_data;
লাস্ট_রো/প্রথম_রো ফাংশন এবং অন্যান্য ক্যাশে সেটিংসের জন্য অপ্টিমাইজ করার জন্য প্রতিটি টেবিলের জন্য কনফিগারেশন বিকল্প রয়েছে। আমি TDEngine ডকুমেন্টেশন পড়ার পরামর্শ দিচ্ছি।
সহজ সংস্করণ: এই নিবন্ধে, আমরা একটি TDEngine টাইম-সিরিজ ডাটাবেস সেট আপ করেছি এবং ক্লায়েন্ট অ্যাপ্লিকেশনগুলিকে সংযোগ করতে এবং ডেটা জিজ্ঞাসা করার অনুমতি দেওয়ার জন্য একটি GraphQL স্কিমা সংজ্ঞায়িত করেছি।
এটা আরো অনেক আছে. আমাদের কাছে একটি স্বচ্ছ ইন্টারফেসে রিলেশনাল ডেটার সাথে জটিল সময়-সিরিজ ডেটা একত্রিত করার জন্য একটি বয়লারপ্লেট প্রকল্প রয়েছে। নেভাডোসে, আমরা একটি প্রাথমিক ডাটাবেস হিসাবে PostgreSQL ব্যবহার করছি এবং উপরের movement
উদাহরণের মতোই টাইম-সিরিজ ডেটা পুনরুদ্ধার করছি। এটি একটি একক API-এ একাধিক উত্স থেকে ডেটা একত্রিত করার একটি দুর্দান্ত উপায়। আরেকটি সুবিধা হল যে ডেটা শুধুমাত্র অনুরোধ করা হলেই আনা হয়, যা ক্লায়েন্ট অ্যাপ্লিকেশনে অনেক নমনীয়তা যোগ করে। শেষ কিন্তু অন্তত নয়, GraphQL স্কিমা একটি ডকুমেন্টেশন এবং চুক্তি হিসাবে কাজ করে, তাই আমরা সহজেই "API ডকুমেন্টেশন" বাক্সে টিক দিতে পারি।
আপনার যদি কোন প্রশ্ন বা মন্তব্য থাকে , অনুগ্রহ করে BlueSky-এ যোগাযোগ করুন বা GitHub-এ আলোচনায় যোগ দিন ।
এছাড়াও এখানে প্রকাশিত.