12/08/2018, 12:21

Tìm kiếm với elasticsearch: cơ bản và nâng cao

Elastic search một search engine server có ưu thế về sự ổn định, tốc độ cao, dễ sử dụng và độc lập với các hệ quản trị cơ sở dữ liệu như SQL. Việc giao tiếp với Elastic server có thể được thực hiện dễ dàng thông qua giao thức http. Chỉ cần nắm được các câu lệnh truy vấn là có thể dễ dàng điều ...

Elastic search một search engine server có ưu thế về sự ổn định, tốc độ cao, dễ sử dụng và độc lập với các hệ quản trị cơ sở dữ liệu như SQL. Việc giao tiếp với Elastic server có thể được thực hiện dễ dàng thông qua giao thức http. Chỉ cần nắm được các câu lệnh truy vấn là có thể dễ dàng điều khiển, tìm kiếm hoặc thậm chí tự viết một API cho ngôn ngữ khác một cách dễ dàng.

Bài viết nhằm mục đích hướng dẫn sử dụng một số câu truy vấn từ cơ bản đến phức tạp của Elastic search. Mọi chí tiết có thể tham khảo trên trang doc chính thức của Elastic search: https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html

Match query

Ta bắt đầu với tìm kiếm đơn giản nhất: tìm kiếm bằng. Ví dụ muốn tìm id bằng 1, ta có hai cách:

  • Cách 1:
{
    "match" : {
        "id" : "1"
    }
}
  • Cách 2:
{
    "term" : {
        "id" : "1"
    }
}

Trong trường hợp này, việc sử dụng match query và term query là tương đương.

String query

Để truy vấn một xâu, ta cũng có thể sử dụng match query để tìm kiếm đúng như trong phần trên. Ngoài ra, để truy vấn chỉ một phần nhỏ trong chuỗi, ta có thể dùng một trong các cách sau:

  • Cách 1:
{
    "match" : {
        "message" : {
            "query" : "pre",
            "type" : "phrase_prefix"
        }
    }
}

Query này có thể tìm được các từ có prefix trong query

  • Cách 2:
{
    "wildcard" : { "name" : "ki*y" }
}

Sử dụng cách này có thể query cùng với các kí tự thay thế đặc biệt trong linux như kí tự '*' dùng để thay thế cho một xâu con bất kì, kí tự '?' để thay thế cho một kí tự bất kì, hoặc truy vấn bằng regular expression.

  • Cách 3:
{
    "query_string" : {
        "default_field" : "content",
        "query" : "this AND that OR thus"
    }
}

Hàm query_string cho phép sử dụng các biểu thức logic AND/OR vào trong câu truy vấn. Thích hợp cho những xử lí phức tạp.

Mỗi cách đều có ưu nhược điểm riêng, vậy nên tùy vào yêu cầu mà sử dụng câu truy vấn hiệu quả nhất.

Range query

Với những trường có giá trị số hoặc thời gian như tuổi, ngày tháng năm sinh, đôi khi ta không cần tìm chính xác mà cần tìm kiếm trong một khoảng nào đó. Vì thế, Elastic search cung cấp range query để tìm kiếm các giá trị theo khoảng.

Tìm kiếm theo khoảng:

{
    "range" : {
        "age" : {
            "gte" : 10,
            "lte" : 20
        }
    }
}

Các hàm so sánh:

  • gte - Lớn hơn hoặc bằng
  • lte - Nhỏ hơn hoặc bằng
  • ge - Lớn hơn
  • le - Nhỏ hơn

Ngoài ra có thể dùng hàm from - to để so sánh khoảng (from - to tương đương với gte - lte).

Một câu range query không bắt buộc phải có đầy đủ các hàm.

Tương tự với tìm kiếm theo khoảng thời gian:

{
    "range" : {
        "birthday" : {
            "ge": "01/01/2012",
            "le": "2013"
        }
    }
}

Multi match query

Để truy vấn trên nhiều trường, thay vì phải viết query trên từng trường một, ta chỉ cần viết một query duy nhất trên tất cả các trường, đó chính là multi match query.

{
    "multi_match" : {
        "query":    "this is a test",
        "fields": ["subject", "message"]
    }
}

Tìm kiếm các kí tự đặc biệt

Elastic search thực hiện đánh index theo từng từ trong đó các kí tự đặc biệt được cũng sử dụng để phân chia các từ với nhau. Điều đó đồng nghĩa với việc, trong điều kiện bình thường, Elastic search sẽ không thực hiện việc đánh index cho các kí tự đặc biệt, nói cách khác là ta không thể thực hiện tìm kiếm khi với các kí tự đặc biệt.

Để giải quyết vấn đề này, ta phải sử dụng phương pháp đánh index đặc biệt, đó là đặt ra các analyzer và tokenizer đặc biệt giúp đánh index cho cả những kí tự đặc biệt này.

{
    "settings" : {
        "analysis" : {
            "analyzer" : {
                "my_ngram_analyzer" : {
                    "tokenizer" : "my_ngram_tokenizer"
                }
            },
            "tokenizer" : {
                "my_ngram_tokenizer" : {
                    "type" : "nGram",
                    "token_chars": ["letter", "digit", "whitespace", "punctuation", "symbol"]
                }
            }
        }
    }
}

Trong đó:

  • letter - Các chữ cái như a, b, ï và 京
  • digit - Các chữ số như 3 và 7
  • whitespace - Các kí tự khoảng trắng như space và
  • punctuation - Các dấu câu như ! và "
  • symbol - Các kí hiệu như @, # và &

Ghép các câu truy vấn

Trong các form search phức tạp, query đòi hỏi nhiều tầng logic, tìm kiếm nhiều trường với nhiều điều kiện khác nhau, ta có thể ghép tất cả các câu truy vần vào trong một câu query duy nhất: đó là bool query. Cấu trúc một câu bool query gồm có 3 phần: must, must_not và should. Mỗi phần gồm một dãy các câu query khác. Chức năng mỗi phần:

  • must: Các kết quả PHẢI thỏa mãn các câu query
  • must_not: Các kết quả PHẢI KHÔNG thỏa mãn các câu query
  • should: Các kết quả thỏa mãn MỘT TRONG các câu query

Như các câu query khác, một câu bool query không bắt buộc phải có đủ ba phần trên.

Đặc biệt, trong mỗi phần của bool query có thể chứa một hoặc nhiều bool query khác! Điều này có nghĩa là việc mở rộng các câu truy vấn là vô hạn!

{
    "bool" : {
        "must" : [
            "term" : {"location" : "hanoi"},
            "term" : {"subject" : "math"},
        ],
        "must_not" : [
            "range" : {
                "age" : { "from" : 10, "to" : 20 }
            }
        ],
        "should" : [
            {
                "term" : { "tag" : "wow" }
            },
            {
                "term" : { "tag" : "elasticsearch" }
            }
        ]
    }
}
0