0

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):

  1. Tokenization (Tách từ) & Stripping HTML: Khi bài viết được lưu, com_finder bó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ữ.

  2. 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).

  3. 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 →\rightarrow Manage →\rightarrow 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ện onContentAfterSave và đẩy dữ liệu sang cho nhóm plugin finder.

  • 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)

  1. Truy cập Components →\rightarrow Smart Search →\rightarrow Index.

  2. 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_time củ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 →\rightarrow Smart Search →\rightarrow 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

  1. Tạo Menu Item trang kết quả (Bắt buộc để có SEF URL đẹp):

    • Vào Menus →\rightarrow Main Menu →\rightarrow Tạo một Menu Item mới kiểu Smart Search →\rightarrow 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).
  2. Tạo Module ô nhập tìm kiếm:

    • Vào Content →\rightarrow Site Modules →\rightarrow Tạo mới một Module kiểu Smart Search.

    • Gán vào vị trí search hoặc topbar củ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:

  1. Truy cập Components →\rightarrow Smart Search →\rightarrow Search Filters →\rightarrow Bấm New.

  2. Đặt tiêu đề bộ lọc (Ví dụ: Lọc Tài liệu Kỹ thuật).

  3. Ở phần cây cấu trúc bên dưới:

    • Tích chọn Search by Type →\rightarrow Chỉ chọn Article.

    • Tích chọn Search by Category →\rightarrow 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).

  4. 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 →\rightarrow Smart Search →\rightarrow 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 →\rightarrow Smart Search →\rightarrow 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ên 100 hoặc 200.

    • Memory Table Limit: Giới hạn số bản ghi trong bảng tạm MEMORY trướ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_terms phì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:

  1. #__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 theo url gốc, route (SEF URL), title, description, state, access (Viewing Access Level) và language.

  2. #__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).

  3. #__finder_links_terms: Bảng Pivot khổng lồ nối N-N giữa link_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 đó.

  4. #__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_finder tìm kiếm nhanh và thông minh hơn hẳn truy vấn LIKE cổ đ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ớp Indexer\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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí