Từ Số 0 Đến Kết Nối Elasticsearch Chuẩn Enterprise Bằng Node.js
Để xây dựng một hệ thống thật sự vững chắc, chúng ta không thể code bừa bãi vào một file. Dù là hướng dẫn từ số 0, mình vẫn sẽ dẫn dắt bạn theo chuẩn Architecture (Kiến trúc) của một dự án thực tế.
Bạn đã sẵn sàng chưa? Bật máy tính lên, hít một hơi thật sâu, và làm theo chính xác từng bước dưới đây nhé!
BƯỚC 0: CHUẨN BỊ "THÚ CƯỠI" ELASTICSEARCH
Để code Node.js kết nối được, bạn phải có một con Elasticsearch đang chạy. Nếu bạn chưa có, cách nhanh nhất là dùng Docker (chỉ tốn 10 giây). Mở Terminal (hoặc CMD) và gõ lệnh này để bật một con Elasticsearch phiên bản mới nhất ở máy tính của bạn:
docker run -d --name elasticsearch -p 9200:9200 -e "discovery.type=single-node" -e "xpack.security.enabled=false" docker.elastic.co/elasticsearch/elasticsearch:8.13.0

Cờ security.enabled=false giúp tắt tạm password để chúng ta dễ dàng test ở local).
BƯỚC 1: KHỞI TẠO DỰ ÁN VÀ MỞ VS CODE
Chúng ta sẽ làm việc như một kỹ sư thực thụ, bắt đầu từ giao diện dòng lệnh (Command Line).
- Mở Terminal (Mac/Linux) hoặc Git Bash / PowerShell (Windows).
- Tạo một thư mục mới mang tên dự án của bạn và di chuyển vào đó:
mkdir vibe-elastic-project
cd vibe-elastic-project

- Khởi tạo một dự án Node.js (tạo ra file package.json):
npm init -y

- Mở thư mục này bằng Visual Studio Code:
code .

Bùm! VS Code của bạn đã mở ra với một thư mục dự án hoàn toàn trống trơn.
BƯỚC 2: CÀI ĐẶT VŨ KHÍ (LIBRARIES)
Trong VS Code, bấm tổ hợp phím ``Ctrl + ``` (nút lùi bên cạnh số 1) để mở Terminal tích hợp sẵn của VS Code.
Chúng ta cần cài 2 thư viện:
- @elastic/elasticsearch: Thư viện chính chủ của Elastic.
- dotenv: Thư viện giúp đọc file môi trường .env (chứa các thông tin nhạy cảm).
Gõ lệnh sau và nhấn Enter:
npm install @elastic/elasticsearch dotenv


BƯỚC 3: XÂY DỰNG CẤU TRÚC THƯ MỤC
Một Vibe Coder không bao giờ ném mọi thứ vào file index.js. Ở thanh bên trái của VS Code (Explorer), hãy tạo các file sau để có cấu trúc như này:
vibe-elastic-project/
├── node_modules/
├── .env <-- Nơi cất giấu bí mật
├── elastic.service.js <-- Lõi kết nối Elasticsearch
├── index.js <-- File chạy chính
├── package.json
└── package-lock.json

BƯỚC 4: CODE TỪNG DÒNG (DÀNH CHO SỰ SỐNG CÒN)
File 1: Cất giấu thông tin kết nối (.env)
Mở file .env lên và viết đúng 1 dòng này. Nếu sau này bạn mua Server thật, bạn chỉ cần sửa link ở file này mà không phải chạm vào code.
ELASTIC_URL=http://localhost:9200
File 2: Trái tim kết nối (elastic.service.js)
Mở file này lên. Đây là nơi thể hiện đẳng cấp "hạng nặng". Chúng ta sẽ dùng mẫu thiết kế Singleton để đảm bảo Node.js chỉ tạo đúng 1 kết nối duy nhất, dù bạn có gọi nó ở 100 file khác nhau.
Viết từng dòng theo mình nhé:
// 1. Kéo thư viện vào
const { Client } = require('@elastic/elasticsearch');
require('dotenv').config(); // Load thông tin từ file .env
class ElasticService {
constructor() {
// 2. Kỹ thuật Singleton: Nếu chưa có kết nối nào thì mới tạo mới
if (!ElasticService.instance) {
console.log('🔄 Đang khởi tạo kết nối đến Elasticsearch...');
// 3. Khởi tạo Client với các thông số "lì đòn"
this.client = new Client({
node: process.env.ELASTIC_URL, // Lấy URL từ file .env
// Cấu hình chịu tải (Resilience)
maxRetries: 3, // Thử gọi lại 3 lần nếu mạng rớt
requestTimeout: 10000, // Hủy nếu Server ES không trả lời sau 10s
});
// 4. Lưu lại kết nối này vào biến static
ElasticService.instance = this;
}
// Nếu đã có kết nối rồi, cứ thế mà lấy ra xài
return ElasticService.instance;
}
// Viết một hàm nhỏ để các file khác lấy cái client này
getClient() {
return this.client;
}
}
// 5. Khởi tạo Class và xuất cái Client ra ngoài
const elasticInstance = new ElasticService();
module.exports = elasticInstance.getClient();
File 3: Bấm nút chạy thử (index.js)
Trái tim đã đập, giờ chúng ta nối nó vào não bộ để chạy thử. Mở index.js và viết:
// 1. Nhập cái client mà chúng ta vừa đúc ở file kia vào
const esClient = require('./elastic.service');
// 2. Viết hàm kiểm tra sức khỏe của Cluster (Cụm ES)
async function checkElasticHealth() {
try {
console.log('📡 Đang gửi request Ping đến Server...');
// Gọi lệnh info() để hỏi thăm xem ES còn sống không
const healthInfo = await esClient.info();
console.log('✅ KẾT NỐI THÀNH CÔNG RỰC RỠ!');
console.log('-----------------------------------');
console.log(`Tên Cluster: ${healthInfo.cluster_name}`);
console.log(`Phiên bản ES: ${healthInfo.version.number}`);
console.log(`Tên Node hiện tại: ${healthInfo.name}`);
console.log('-----------------------------------');
} catch (error) {
// Nếu Server ES chưa bật hoặc sai link, nó sẽ báo lỗi ở đây
console.error('❌ KẾT NỐI THẤT BẠI. Lỗi chi tiết:');
console.error(error.message);
}
}
// 3. Thực thi hàm
checkElasticHealth();
BƯỚC 5: HÁI QUẢ NGỌT
Mọi thứ đã sẵn sàng. Trở lại Terminal của VS Code, hãy gõ lệnh để chạy file index.js:
node index.js
Nếu bạn đã làm đúng mọi thứ và Elasticsearch ở Bước 0 đang chạy, màn hình Console của bạn sẽ in ra một thông báo tuyệt đẹp như thế này:
🔄 Đang khởi tạo kết nối đến Elasticsearch...
📡 Đang gửi request Ping đến Server...
✅ KẾT NỐI THÀNH CÔNG RỰC RỠ!
-----------------------------------
Tên Cluster: docker-cluster
Phiên bản ES: 8.13.0
Tên Node hiện tại: e3b7a8c9d1f2
-----------------------------------

Lời kết
Xin chúc mừng! Bạn không chỉ học được cách kết nối, mà bạn còn sở hữu một bộ khung (Boilerplate) cực kỳ xịn sò.
Bất cứ khi nào bạn muốn thêm file user.controller.js hay product.controller.js, bạn chỉ cần gõ đúng 1 dòng const esClient = require('./elastic.service') là đã có sẵn một cỗ máy kết nối tối ưu, không tốn thêm RAM, không sợ trùng lặp kết nối.
Đó chính là con đường của một Software Engineer thực thụ! Dấu mốc này sẽ mở ra hàng loạt bài toán đỉnh cao về Search sau này.
All rights reserved