+6

Xử lý ngôn ngữ tiếng Nhật (Japanese Analyzer) trong Elasticsearch

1. Giới thiệu

Trong thế giới toàn cầu hóa ngày nay, phục vụ cho các ngôn ngữ và nền văn hóa đa dạng là điều cần thiết để truy xuất và phân tích thông tin hiệu quả. Ngôn ngữ Nhật Bản rất phong phú và phức tạp, đặt ra những thách thức độc đáo cho việc phân tích văn bản. Cần phải có một phương pháp chuyên biệt để đảm bảo lập chỉ mục chính xác, tìm kiếm hiệu quả và xử lý ngôn ngữ chính xác. Và trình phân tích tiếng Nhật (Japanese analyzer) của Elasticsearch ra đời. Cho dù bạn đang xây dựng các ứng dụng tìm kiếm, hệ thống xử lý ngôn ngữ hay phân tích dữ liệu, việc hiểu cách thức hoạt động của Japanese analyzer và tận dụng các tính năng của nó có thể nâng cao đáng kể việc triển khai Elasticsearch của bạn.

2. Hiểu về Elasticsearch Japanese analyzer

2.1. Cốt lõi của Elasticsearch Japanese analyzer là công cụ phân tích hình thái Kuromoji mạnh mẽ

Kuromoji vượt trội trong việc mã hóa văn bản tiếng Nhật, chia nó thành các đơn vị có ý nghĩa được gọi là token, hiểu vai trò ngữ pháp của chúng và cung cấp thông tin chuyên sâu về ngôn ngữ như gắn thẻ một phần của bài phát biểu, trích xuất dạng cơ bản của token (base form) và đọc cách phát âm. Các bạn có thể thử công cụ phân tích Kuromoji ở đây. Hãy copy một câu tiếng Nhật trên Google dịch, paste vào và bấm Tokenize.

Screen Shot 2023-06-07 at 09.34.29.png

Như mình đã thử, các bạn có thể thấy câu tiếng Nhật mình nhập vào (見えた nghĩa là đã thấy) đã được tách ra làm 2 token, gồm các thành phần:

  • Surface form: Nguyên bản từ mà các bạn nhập vào là 見え và た.
  • Part-of-Speech: Loại từ gì, nôm na rằng đây là động từ, danh từ hay gì đó …
  • Base form: Thứ quan trọng nhất, dạng cơ bản của từ. 見え có dạng cơ bản là 見える và た thì dạng cơ bản vẫn là た.
  • Reading: Cách đọc ミエタ mi-e-ta
  • Pronunciation: Cách phát âm ミエタ mi-e-ta

Dù không hiểu nhiều về tiếng Nhật, nhưng khi tra cứu từ điển hoặc nhập vào một câu tiếng Nhật, Kuromoji trả về cho ta các token với dạng base form của token đó. Và đó cũng là cách cơ bản để Elasticsearch Japanese Analyzer thực hiện việc phân tích tiếng Nhật.

2.2. Tính năng của Elasticsearch Japanese analyzer

2.2.1. Cơ bản

Là một analyzer trong Elasticsearch, Japanese analyzer cũng có 2 thành phần cơ bản:

  • Tokenizer: Chịu trách nhiệm tách văn bản thành các token. Elasticsearch cung cấp cho ta một tokenizer chuyên dụng cho tiếng Nhật là kuromoji_tokenizer. Bản chất là sử dụng Kuromoji để tách văn bản thành các token (surface form) như mình đã thử ở trên.
  • Filter: Chịu trách nhiệm biến đổi các token về dạng dễ tìm kiếm nhất (thông thường sẽ biến đổi lowercase). Elasticsearch cung cấp một filter chuyên dụng cho tiếng Nhật là kuromoji_stemmer. Bản chất là biến đổi các token từ dạng surface form về dạng base form.

Tóm tắt lại, đầu vào của analyzer là một văn bản, đầu ra sẽ là các token được tách và biển đổi từ văn bản đó. Và những gì Japanese analyzer cho ra chính là các token dạng base form mà ta có thể dễ dàng lấy được từ trang Kuromoji demo bên trên.

2.2.2. Dictionary và Synonym

Ngoài ra, Elasticsearch cung cấp cho chúng ta khả năng tự custom, thêm thắt tokenizer và filter theo chủ đích của mình bằng cách thêm vào các file dictionary và synonym mà ta tự viết.

Dictionary

Là một file text, mỗi dòng có cú pháp là text,tokens,readings,part-of-speech

  • Text: Từ ghép hoặc cụm từ xuất hiện trong nội dung của bạn.
  • Tokens: Đây chính là các token được trả về, được viết cách nhau bởi khoảng trắng
  • Reading: Chứa cùng một văn bản như token với bất kỳ chữ kanji nào được thay thế bằng katakana. Điều này mô tả cách phát âm của các mã thông báo
  • Part-of-speech: Xác định văn bản là gì, ví dụ như một danh từ hoặc động từ Kết quả, khi phát hiện ra đoạn text mà bạn đã quy định, nó sẽ trả về các token mà bạn muốn.

Synonym

Là một file text, mỗi dòng là định nghĩa một tập hợp các từ đồng nghĩa với nhau, cách nhau bởi dấu phẩy. Kết quả, khi token được tìm thấy trong file này, Elasticsearch sẽ trả về tất cả các từ nằm cùng dòng với token đó.

3. Thực hành

Hãy cùng thực hành để hiểu rõ hơn về các nội dung trên nhé! Mình sẽ sử dụng Docker để cài đặt Elasticsearch.

3.1. Khởi tạo

Tạo project mới:

mkdir elasticsearch_analyzer_practice
cd elasticsearch_analyzer_practice

Tạo 2 file khai báo dictionary và synonym

東京スカイツリー,東京 スカイツリー,トウキョウ スカイツリー,名詞
海,海面,海原,綿津見

Tạo Dockerfile như sau:

FROM docker.elastic.co/elasticsearch/elasticsearch:7.17.7
RUN elasticsearch-plugin install analysis-kuromoji
COPY ja_synonym.txt /usr/share/elasticsearch/config/ja_synonym.txt
COPY ja_dictionary.txt /usr/share/elasticsearch/config/ja_dictionary.txt

Trong này, mình sử dụng Elasticsearch 7.17.7 và cài đặt plugin analysis-kuromoji. Copy 2 file ja_synonym.txt và ja_dictionary.txt vào folder config. Tạo docker-compose file:

version: '2.2'
services:
  es:
    build: ./
    container_name: es
    environment:
      - node.name=es
      - cluster.name=es-docker-cluster
      - cluster.initial_master_nodes=es
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data01:/usr/local/share/elasticsearch/data
    ports:
      - 9200:9200
    networks:
      - elastic
  kibana:
    image: docker.elastic.co/kibana/kibana:7.17.7
    container_name: kibana
    environment: 
      - ELASTICSEARCH_HOSTS=["http://es:9200"]
    depends_on:
      - es
    ports:
      - 5601:5601 
    networks:
      - elastic 
volumes:
  data01:
    driver: local

networks:
  elastic:
    driver: bridge

Trong file compose, mình chạy 2 service là elasticsearch ở cổng 9200 và Kibana ở cổng 5601. Mình sẽ sử dụng console Kibana để thao tác với Elasticsearch dễ dàng hơn. Sau đó chạy docker-compose lên thôi

docker-compose up --build

3.2. Chạy thử

Sử dụng Kibana console ở đường dẫn http://localhost:5601/app/dev_tools#/console Đầu tiên là tạo Index:

PUT /demo
{
  "settings": {
    "number_of_shards": 1,
    "index": {
      "analysis": {
        "filter": {
          "ja_synonym": {
            "updateable": "true",
            "type": "synonym_graph",
            "synonyms_path": "ja_synonym.txt",
            "lenient": "true"
          }
        },
        "tokenizer": {
          "kuromoji_tokenizer_dictionary": {
            "type": "kuromoji_tokenizer",
            "user_dictionary": "ja_dictionary.txt"
          },
          "ja_tokenizer": {
            "type": "kuromoji_tokenizer"
          }
        },
        "analyzer": {
          "ja_analyzer": {
            "filter": [
              "kuromoji_stemmer",
              "cjk_width",
              "lowercase"
            ],
            "tokenizer": "ja_tokenizer"
          },
          "ja_analyzer_dictionary": {
            "filter": [
              "kuromoji_stemmer",
              "cjk_width",
              "lowercase"
            ],
            "tokenizer": "kuromoji_tokenizer_dictionary"
          },
          "ja_analyzer_synonym": {
            "filter": [
              "kuromoji_stemmer",
              "cjk_width",
              "lowercase",
              "ja_synonym"
            ],
            "tokenizer": "ja_tokenizer"
          }
        }
      }
    }
  }
}

Hãy xem mình đã setting gì cho Index này nhé:

  • Khai báo 1 filter tên là ja_synonym sử dụng file ja_synonym.txt.
  • Khai báo 2 tokenizer là ja_tokenizer chỉ sử dụng Kuromoji và ja_tokenizer_custom có sử dụng cả file ja_dictionary.txt.
  • Khai báo 3 analyzer:
    • ja_analyzer sử dụng Kuromoji mặc định.
    • ja_analyzer_dictionary sử dụng thêm dictionary.
    • ja_analyzer_synonym sử dụng thêm filter synonym. Giờ hãy xem các analyzer hoạt động như nào nhé.

3.2.1. Analyzer chỉ sử dụng Kuromoji cơ bản

GET /demo/_analyze
{
  "analyzer" : "ja_analyzer",
  "text" : "東京スカイツリー"
}

Kết quả:

{
  "tokens" : [
    {
      "token" : "東京",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "スカイ",
      "start_offset" : 2,
      "end_offset" : 5,
      "type" : "word",
      "position" : 1
    },
    {
      "token" : "ツリー",
      "start_offset" : 5,
      "end_offset" : 8,
      "type" : "word",
      "position" : 2
    }
  ]
}

Analyzer ja_analyzer tách text 東京スカイツリー thành 3 token 東京, スカイツリー đúng theo từ điển Kuromoji.

3.2.2. Analyzer có thêm dictionary

GET /demo/_analyze
{
  "analyzer" : "ja_analyzer_dictionary",
  "text" : "東京スカイツリー"
}

Kết quả:

{
  "tokens" : [
    {
      "token" : "東京",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "スカイツリ",
      "start_offset" : 2,
      "end_offset" : 8,
      "type" : "word",
      "position" : 1
    }
  ]
}

Analyzer ja_analyzer_custom chỉ tách text 東京スカイツリー thành 2 token 東京スカイツリ. Lý do vì mình đã quy định text này trong file dictionary.txt.

3.2.3. Analyzer có thêm synonym

GET /demo/_analyze
{
  "analyzer" : "ja_analyzer_synonym",
  "text" : "海面"
}

Kết quả:

{
  "tokens" : [
    {
      "token" : "海",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "SYNONYM",
      "position" : 0
    },
    {
      "token" : "海原",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "SYNONYM",
      "position" : 0
    },
    {
      "token" : "綿津見",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "SYNONYM",
      "position" : 0
    },
    {
      "token" : "海面",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "word",
      "position" : 0
    }
  ]
}

Kết quả được tách thành rất nhiều token do anazyler ja_analyzer_synonym có sử dụng synonym mà mình đã quy định cho từ 海面.

4. Tiểu kết

Như vậy, chúng ta đã vừa cùng tìm hiểu về trình phân tích tiếng Nhật (Japanese analyzer) của Elasticsearch. Tôi hy vọng bài viết trên sẽ hữu ích đối với các bạn. Hãy chia sẻ câu hỏi hoặc suy nghĩ của bạn về bài viết dưới phần comment nhé!

🔗 Tìm hiểu thêm về Pixta Vietnam: http://bit.ly/3kdkzvW


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í