Joomla Bài học 17: Thiết lập tìm kiếm thông minh (Smart Search / Finder) và lập chỉ mục nội dung (Indexing)
Bắt đầu từ Joomla 4 và hoàn thiện mạnh mẽ ở Joomla 5, thành phần tìm kiếm cổ điển (com_search dựa trên truy vấn WHERE title LIKE '%keyword%' gây Full Table Scan) đã bị loại bỏ hoàn toàn khỏi hệ thống. Thay thế cho nó là Smart Search (com_finder) — một bộ máy tìm kiếm dựa trên kiến trúc Inverted Index (Chỉ mục đảo ngược) tương tự như cách Elasticsearch hay Apache Solr vận hành ở quy mô thu nhỏ ngay trong MySQL.
Trong Joomla Bài học 17, chúng ta sẽ tìm hiểu kiến trúc phân tách từ vựng (Tokenization & Stemming) của com_finder, quy trình lập chỉ mục dữ liệu qua Web UI và CLI, cách thiết lập bộ lọc tìm kiếm chuyên sâu (Search Filters) và giải phẫu cách viết một Finder Plugin để đưa dữ liệu của Component tự viết vào bộ máy tìm kiếm chung.
1. Bản chất kỹ thuật: Tại sao Smart Search (com_finder) lại vượt trội?
Nếu truy vấn LIKE '%...%' truyền thống buộc MySQL phải quét qua toàn bộ nội dung HTML của hàng vạn bài viết mỗi khi người dùng gõ tìm kiếm, thì Smart Search (com_finder) xử lý việc nặng đó ngay tại thời điểm bài viết được lưu vào Database (Index-time processing):
-
Tokenization (Tách từ) & Stripping HTML: Khi bài viết được lưu,
com_finderbóc tách sạch các thẻ HTML, chia văn bản thành các từ đơn lẻ (Tokens) và các cụm từ ghép 2-3 chữ. -
Weight Calculation (Tính điểm trọng số TF-IDF rút gọn): Hệ thống tự động gán điểm ưu tiên dựa trên vị trí xuất hiện của từ khóa:
-
Từ khóa nằm trong Title (Tiêu đề): Hệ số nhân trọng số cao nhất (Mặc định:
1.7). -
Từ khóa nằm trong Body (Nội dung): Hệ số trung bình (
0.7). -
Từ khóa nằm trong Meta / Category / Author: Hệ số phụ trợ (
0.8-1.2).
-
-
Auto-Completion (Gợi ý tự động) & Did-you-mean: Nhờ có bảng từ điển các token đã được tách sẵn trong bảng
#__finder_terms, ngay khi người dùng gõ 2-3 ký tự đầu tiên vào ô tìm kiếm, Joomla có thể trả về danh sách gợi ý từ khóa (AJAX Autocomplete) trong vài mili-giây.
2. Quy trình 4 bước kích hoạt và lập chỉ mục (Indexing) cho Smart Search
Bước 1: Kích hoạt chuỗi Plugin lắng nghe sự kiện (Content - Smart Search & Smart Search - *)
Để hệ thống tự động cập nhật chỉ mục mỗi khi bạn thêm/sửa/xóa bài viết, bạn cần đảm bảo các plugin sau đã bật tại System Manage Plugins:
-
Content - Smart Search (Nhóm
content): Đây là plugin cực kỳ quan trọng đóng vai trò làm "cầu nối" bắt sự kiệnonContentAfterSavevà đẩy dữ liệu sang cho nhóm pluginfinder. -
Nhóm plugin
finder(Smart Search - ...): Bạn muốn cho phép người dùng tìm kiếm loại dữ liệu nào thì bật plugin đó (Ví dụ: Smart Search - Content, Smart Search - Categories, Smart Search - Tags, Smart Search - Contacts).
Bước 2: Chạy lập chỉ mục lần đầu (Initial Indexing)
-
Truy cập Components Smart Search Index.
-
Nếu bảng danh sách đang trống, hệ thống sẽ hiển thị thông báo nhắc bạn bấm nút Index trên thanh công cụ góc trên bên trái. 3.Một cửa sổ Popup tiến trình (Batch Processing bằng AJAX) sẽ chạy và quét qua toàn bộ các bài viết, danh mục hiện có để bóc tách từ vựng.
Sử dụng Joomla CLI cho cơ sở dữ liệu lớn (Dành cho Backend Engineer):
Nếu website có từ 10.000 bài viết trở lên, việc chạy Index trên trình duyệt rất dễ bị đứt quãng do giới hạn
max_execution_timecủa PHP-FPM hoặc Nginx Timeout. Thay vào đó, hãy chạy trực tiếp bằng Joomla CLI trong container Docker:Bash
# Chạy lập chỉ mục toàn bộ dữ liệu qua CLI docker exec -it joomla_php php cli/joomla.php finder:index # Xóa sạch chỉ mục cũ (Purge) và lập chỉ mục lại từ đầu docker exec -it joomla_php php cli/joomla.php finder:index --purge
Bước 3: Kiểm tra Content Maps (Bản đồ phân loại nội dung)
Truy cập Components Smart Search Content Maps. Tại đây, Joomla tự động gom nhóm các tài nguyên đã lập chỉ mục thành các nhánh (Branches) như:
-
Type: Article, Category, Tag...
-
Category: Tin tức, Công nghệ, Tuyển dụng...
-
Author: Nguyễn Văn A, Trần Thị B...
-
Language:
vi-VN,en-GB...
Bước 4: Đưa thanh tìm kiếm và Trang kết quả ra ngoài Frontend
-
Tạo Menu Item trang kết quả (Bắt buộc để có SEF URL đẹp):
- Vào Menus Main Menu Tạo một Menu Item mới kiểu Smart Search Search. Đặt tên là Tìm kiếm (Alias:
tim-kiem). Bạn có thể bật tùy chọn Display in Menu = No nếu không muốn nút này hiện trên thanh menu ngang, nhưng Router sẽ dùng nó để tạo đường dẫn[domain.com/tim-kiem?q=joomla](https://domain.com/tim-kiem?q=joomla).
- Vào Menus Main Menu Tạo một Menu Item mới kiểu Smart Search Search. Đặt tên là Tìm kiếm (Alias:
-
Tạo Module ô nhập tìm kiếm:
-
Vào Content Site Modules Tạo mới một Module kiểu Smart Search.
-
Gán vào vị trí
searchhoặctopbarcủa Template. -
Tại mục Search Filter, bạn có thể chọn gắn cứng một bộ lọc nếu muốn ô tìm kiếm này chỉ tìm trong một khu vực nhất định (ví dụ: chỉ tìm trong danh mục Tài liệu kỹ thuật).
-
3. Thiết lập Search Filters (Bộ lọc tìm kiếm nâng cao)
Giả sử website của bạn vừa có Tin tức công ty, vừa có Tài liệu hướng dẫn sản phẩm, bạn muốn tạo một trang tìm kiếm chuyên biệt chỉ quét các bài viết thuộc mục Tài liệu hướng dẫn:
-
Truy cập Components Smart Search Search Filters Bấm New.
-
Đặt tiêu đề bộ lọc (Ví dụ: Lọc Tài liệu Kỹ thuật).
-
Ở phần cây cấu trúc bên dưới:
-
Tích chọn Search by Type Chỉ chọn
Article. -
Tích chọn Search by Category Chỉ chọn danh mục
Tài liệu hướng dẫn. -
Có thể giới hạn thêm theo khoảng thời gian (Start Date / End Date).
-
-
Lưu lại và gắn bộ lọc này vào Menu Item hoặc Module Smart Search.
4. Tinh chỉnh hiệu năng & Bộ nhớ trong Smart Search Options
Truy cập Components Smart Search Bấm nút Options (góc trên bên phải):
-
Tab Smart Search (Hiển thị):
-
Show Autocomplete: Bật Yes để kích hoạt tính năng gợi ý từ khóa khi gõ.
-
Show Advanced Search: Cho phép người dùng mở rộng khung lọc theo tác giả, danh mục, ngày đăng ngoài Frontend.
-
Gather Search Statistics: Bật Yes nếu bạn muốn thống kê xem khách hàng hay gõ từ khóa gì vào web của bạn (Xem báo cáo tại mục Components Smart Search Search Term Analysis).
-
-
Tab Index (Tối ưu hóa thuật toán):
-
Indexer Batch Size: Số lượng bản ghi xử lý trong 1 lô (Mặc định là
50). Nếu server nhiều RAM có thể tăng lên100hoặc200. -
Memory Table Limit: Giới hạn số bản ghi trong bảng tạm
MEMORYtrước khi chuyển sang ổ đĩa. -
Enable Tuplecount / Common Words: Nếu cơ sở dữ liệu bài viết quá lớn (hàng trăm ngàn bài), hãy chuyển Phrase Searching (Tìm kiếm cụm từ) sang Disabled để ngăn bảng
#__finder_termsphình to gấp 3-4 lần do lưu các cụm từ ghép 2-3 từ.
-
5. Giải phẫu Database & Cách viết Finder Plugin cho Custom Component (Góc nhìn Backend)
Kiến trúc các bảng #__finder_* trong MySQL
Khi com_finder hoạt động, dữ liệu được phân rã vào 4 bảng cốt lõi sau:
-
#__finder_links: Lưu danh sách từng thực thể (Bài viết, Danh mục...) đã được lập chỉ mục kèm theourlgốc,route(SEF URL),title,description,state,access(Viewing Access Level) vàlanguage. -
#__finder_terms: Từ điển lưu toàn bộ các từ vựng độc nhất (term), ngôn ngữ, và trọng số cơ bản (weight). -
#__finder_links_terms: Bảng Pivot khổng lồ nối N-N giữalink_id(bài viết) vàterm_id(từ vựng), kèm theo điểm số tính toán cuối cùng (weight) của từ đó trong bài viết đó. -
#__finder_taxonomy: Lưu cây phân loại (Type, Category, Author, Language) theo cấu trúc Nested Set để lọc kết quả siêu tốc.
Cấu trúc một Finder Plugin chuẩn Joomla 5 (Lập trình mở rộng)
Khi bạn tự viết một Component ở Phần 5 (ví dụ: Component quản lý khóa học com_courses), để đưa các khóa học vào bộ máy Smart Search, bạn chỉ cần viết một Plugin kế thừa lớp Joomla\Component\Finder\Administrator\Indexer\Adapter:
PHP
namespace MyCompany\Plugin\Finder\Courses\Extension;
use Joomla\Component\Finder\Administrator\Indexer\Adapter;
use Joomla\Component\Finder\Administrator\Indexer\Helper;
use Joomla\Component\Finder\Administrator\Indexer\Indexer;
use Joomla\Component\Finder\Administrator\Indexer\Result;
use Joomla\Database\DatabaseQuery;
\defined('_JEXEC') or die;
final class Courses extends Adapter
{
protected $context = 'Courses';
protected $extension = 'com_courses';
protected $layout = 'course';
protected $type_title = 'Course';
protected $table = '#__courses';
protected function setup(): bool
{
return true;
}
/**
* Bước 1: Định nghĩa câu lệnh SQL lấy dữ liệu từ bảng #__courses để đưa vào Indexer
*/
protected function getListQuery($query = null): DatabaseQuery
{
$db = $this->getDatabase();
$query = $query instanceof DatabaseQuery ? $query : $db->getQuery(true);
$query->select('a.id, a.title, a.alias, a.summary AS body, a.state, a.access, a.language')
->select('a.catid, a.created AS start_date, a.price')
->from($db->quoteName('#__courses', 'a'));
return $query;
}
/**
* Bước 2: Biến đổi từng bản ghi (Result) và khai báo Taxonomy trước khi băm từ khóa
*/
protected function index(Result $item): void
{
// Xây dựng URL gốc và SEF Route cho khóa học
$item->url = $this->getURL($item->id, $this->extension, $this->layout);
$item->route = 'index.php?option=com_courses&view=course&id=' . $item->id . ':' . $item->alias;
// Dịch các tham số và thêm vào nhánh phân loại (Taxonomy)
$item->addTaxonomy('Type', 'Course');
$item->addTaxonomy('Language', $item->language);
// Nếu muốn cho phép người dùng tìm kiếm cả theo Mã khóa học hoặc Giá tiền:
$item->addInstruction(Indexer::META_CONTEXT, 'price');
// Gọi Indexer cốt lõi của Joomla để bóc tách từ vựng và lưu vào #__finder_links_terms
$this->indexer->index($item);
}
}
6. Tổng kết bài học
-
Hiểu rõ cơ chế Inverted Index và tính điểm trọng số (Weight Calculation) giúp
com_findertìm kiếm nhanh và thông minh hơn hẳn truy vấnLIKEcổ điển. -
Nắm vững quy trình kích hoạt plugin, chạy lập chỉ mục qua Joomla CLI (
finder:index), cấu hình Search Filters và theo dõi từ khóa qua Search Term Analysis. -
Hiểu cấu trúc các bảng
#__finder_*trong MySQL và cách kế thừa lớpIndexer\Adapterđể tích hợp Smart Search vào bất kỳ Custom Component nào.
Trong Bài học 18, chúng ta sẽ bước vào pháo đài phòng thủ quan trọng nhất của một hệ thống Production: Bảo mật Joomla toàn diện: Xác thực đa yếu tố (MFA/Passkeys), cấu hình .htaccess và HTTP Security Headers.
All rights reserved