Lindera
lindera トークナイザーは、辞書ベースの形態素解析を行います。日本語と韓国語向けに設計されており、これらの言語では単語がスペースで区切られず、文法的な標識(助詞)が単語に直接付加されます。
中国語のテキストの場合: lindera は cc-cedict 辞書を介して中国語をサポートしていますが、代わりに jieba トークナイザーを使用することをお勧めします。Jieba は中国語の単語分割用に特別に設計されており、より良い結果を提供します。
概要
日本語と韓国語は膠着語です。助詞と呼ばれる文法的な標識が名詞に直接付加され、多数の組み合わせを形成します。例を以下に示します。
言語 | 元の単語 |
| = 結合形 | 意味 |
|---|---|---|---|---|
韓国語 | 서울(ソウル) | 에서 | 서울에서 | ソウルで |
日本語 | 東京(Tokyo) | に | 東京に | 東京へ |
lindera トークナイザーは次の処理を行います。
-
テキストを分割し、個々の形態素(単語と助詞)に分けます
-
各トークンにタグを付与し、辞書の品詞(POS)情報を付けます
-
フィルターを適用して、不要なトークン(助詞や句読点など)を削除します
この 2 段階のプロセス(分割と、それに続く品詞ベースのフィルタリング)により、検索用にインデックスされるトークンを正確に制御できます。
構成
lindera トークナイザーを使用してアナライザーを構成するには、tokenizer.type を lindera に設定し、dict_kind で辞書を選択し、必要に応じてフィルターを適用します。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
analyzer_params = {
"tokenizer": {
"type": "lindera",
"dict_kind": "ko-dic",
"filter": [
{
"kind": "korean_stop_tags",
"tags": ["SP", "SSC", "SSO", "SC", "SE", "SF", "JKS", "JKC", "JKG", "JKO", "JKB", "JKV", "JKQ", "JX", "JC", "UNK", "EP", "ETM"]
}
]
}
}
Map<String, Object> analyzerParams = new HashMap<>();
analyzerParams.put("tokenizer", new HashMap<String, Object>() {{
put("type", "lindera");
put("dict_kind", "ko-dic");
put("filter", Arrays.asList(
new HashMap<String, Object>() {{
put("kind", "korean_stop_tags");
put("tags", Arrays.asList(
"SP", "SSC", "SSO", "SC", "SE", "SF",
"JKS", "JKC", "JKG", "JKO", "JKB", "JKV", "JKQ",
"JX", "JC", "UNK", "EP", "ETM"
));
}}
));
}});
analyzerParams := map[string]interface{}{
"tokenizer": map[string]interface{}{
"type": "lindera",
"dict_kind": "ko-dic",
"filter": []interface{}{
map[string]interface{}{
"kind": "korean_stop_tags",
"tags": []string{
"SP", "SSC", "SSO", "SC", "SE", "SF",
"JKS", "JKC", "JKG", "JKO", "JKB", "JKV", "JKQ",
"JX", "JC", "UNK", "EP", "ETM",
},
},
},
},
}
fmt.Println(analyzerParams)
use serde_json::json;
let analyzer_params = json!({
"tokenizer": {
"type": "lindera",
"dict_kind": "ko-dic",
"filter": [
{
"kind": "korean_stop_tags",
"tags": ["SP", "SSC", "SSO", "SC", "SE", "SF", "JKS", "JKC", "JKG", "JKO", "JKB", "JKV", "JKQ", "JX", "JC", "UNK", "EP", "ETM"]
}
]
}
});
nlohmann::json analyzer_params = {
{"tokenizer", {
{"type", "lindera"},
{"dict_kind", "ko-dic"},
{"filter", {{
{"kind", "korean_stop_tags"},
{"tags", {"SP", "SSC", "SSO", "SC", "SE", "SF", "JKS", "JKC", "JKG", "JKO", "JKB", "JKV", "JKQ", "JX", "JC", "UNK", "EP", "ETM"}}
}}}
}}
};
const analyzer_params = {
"tokenizer": {
"type": "lindera",
"dict_kind": "ko-dic",
"filter": [
{
"kind": "korean_stop_tags",
"tags": ["SP", "SSC", "SSO", "SC", "SE", "SF", "JKS", "JKC", "JKG", "JKO", "JKB", "JKV", "JKQ", "JX", "JC", "UNK", "EP", "ETM"]
}
]
}
};
export CLUSTER_ENDPOINT="YOUR_CLUSTER_ENDPOINT"
export TOKEN="YOUR_CLUSTER_TOKEN"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/common/run_analyzer" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"analyzerParams": "{\"tokenizer\":{\"type\":\"lindera\",\"dict_kind\":\"ko-dic\",\"filter\":[{\"kind\":\"korean_stop_tags\",\"tags\":[\"SP\",\"SSC\",\"SSO\",\"SC\",\"SE\",\"SF\",\"JKS\",\"JKC\",\"JKG\",\"JKO\",\"JKB\",\"JKV\",\"JKQ\",\"JX\",\"JC\",\"UNK\",\"EP\",\"ETM\"]}]}}",
"text": ["서울에서 맛있는 음식을 먹었습니다"]
}'
パラメーター | 説明 |
|---|---|
| トークナイザーのタイプです。 |
| 語彙を定義するために使用する辞書です。指定できる値は次のとおりです:
|
| 分割後に適用するトークナイザーレベルのフィルターのリストです。各フィルターは次の項目を持つオブジェクトです:
|
analyzer_params を定義した後、コレクションスキーマを定義する際に、それらを VARCHAR フィールドに適用できます。これにより、Zilliz Cloud は指定したアナライザーを使用してそのフィールド内のテキストを処理し、効率的なトークン化とフィルタリングを行えます。詳細については、使用例 を参照してください。
例
アナライザーの構成をコレクションスキーマに適用する前に、run_analyzer メソッドを使用してその動作を確認します。
韓国語の例
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
from pymilvus import MilvusClient
client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT")
analyzer_params = {
"tokenizer": {
"type": "lindera",
"dict_kind": "ko-dic",
"filter": [
{
"kind": "korean_stop_tags",
"tags": ["SP", "SSC", "SSO", "SC", "SE", "SF", "JKS", "JKC", "JKG", "JKO", "JKB", "JKV", "JKQ", "JX", "JC", "UNK", "EP", "ETM"]
}
]
}
}
# Sample Korean text: "서울에서 맛있는 음식을 먹었습니다" (I ate delicious food in Seoul)
sample_text = "서울에서 맛있는 음식을 먹었습니다"
result = client.run_analyzer(sample_text, analyzer_params)
print("Analyzer output:", result)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.vector.request.RunAnalyzerReq;
import io.milvus.v2.service.vector.response.RunAnalyzerResp;
import java.util.*;
ConnectConfig config = ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.build();
MilvusClientV2 client = new MilvusClientV2(config);
Map<String, Object> analyzerParams = new HashMap<>();
analyzerParams.put("tokenizer", new HashMap<String, Object>() {{
put("type", "lindera");
put("dict_kind", "ko-dic");
put("filter", Arrays.asList(
new HashMap<String, Object>() {{
put("kind", "korean_stop_tags");
put("tags", Arrays.asList(
"SP", "SSC", "SSO", "SC", "SE", "SF",
"JKS", "JKC", "JKG", "JKO", "JKB", "JKV", "JKQ",
"JX", "JC", "UNK", "EP", "ETM"
));
}}
));
}});
List<String> texts = new ArrayList<>();
texts.add("서울에서 맛있는 음식을 먹었습니다");
RunAnalyzerResp resp = client.runAnalyzer(RunAnalyzerReq.builder()
.texts(texts)
.analyzerParams(analyzerParams)
.build());
List<RunAnalyzerResp.AnalyzerResult> results = resp.getResults();
import (
"context"
"fmt"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
ctx := context.Background()
client, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: "YOUR_CLUSTER_ENDPOINT",
APIKey: "YOUR_CLUSTER_TOKEN",
})
if err != nil {
fmt.Println(err.Error())
// handle error
}
analyzerParams := map[string]interface{}{
"tokenizer": map[string]interface{}{
"type": "lindera",
"dict_kind": "ko-dic",
"filter": []interface{}{
map[string]interface{}{
"kind": "korean_stop_tags",
"tags": []string{
"SP", "SSC", "SSO", "SC", "SE", "SF",
"JKS", "JKC", "JKG", "JKO", "JKB", "JKV", "JKQ",
"JX", "JC", "UNK", "EP", "ETM",
},
},
},
},
}
texts := []string{"서울에서 맛있는 음식을 먹었습니다"}
option := milvusclient.NewRunAnalyzerOption(texts...).
WithAnalyzerParams(analyzerParams)
_, err = client.RunAnalyzer(ctx, option)
if err != nil {
fmt.Println(err.Error())
// handle error
}
use milvus::v2::prelude::*;
use serde_json::json;
let config = ConnectConfig::new().uri("YOUR_CLUSTER_ENDPOINT");
let client = ClientV2::new(&config).await?;
let analyzer_params = json!({
"tokenizer": {
"type": "lindera",
"dict_kind": "ko-dic",
"filter": [
{
"kind": "korean_stop_tags",
"tags": ["SP", "SSC", "SSO", "SC", "SE", "SF", "JKS", "JKC", "JKG", "JKO", "JKB", "JKV", "JKQ", "JX", "JC", "UNK", "EP", "ETM"]
}
]
}
});
let run_analyzer_req = RunAnalyzerRequest::builder()
.texts(vec!["서울에서 맛있는 음식을 먹었습니다"])
.analyzer_params(analyzer_params)
.build()?;
let res = client.run_analyzer(run_analyzer_req).await?;
println!("{:?}", res.results());
#include "milvus/MilvusClientV2.h"
#include <iostream>
auto client = milvus::MilvusClientV2::Create();
milvus::ConnectParam connect_param{"YOUR_CLUSTER_ENDPOINT"};
auto status = client->Connect(connect_param);
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
nlohmann::json analyzer_params = {
{"tokenizer", {
{"type", "lindera"},
{"dict_kind", "ko-dic"},
{"filter", {{
{"kind", "korean_stop_tags"},
{"tags", {"SP", "SSC", "SSO", "SC", "SE", "SF", "JKS", "JKC", "JKG", "JKO", "JKB", "JKV", "JKQ", "JX", "JC", "UNK", "EP", "ETM"}}
}}}
}}
};
milvus::RunAnalyzerResponse response;
status = client->RunAnalyzer(milvus::RunAnalyzerRequest()
.WithTexts({"서울에서 맛있는 음식을 먹었습니다"})
.WithAnalyzerParams(analyzer_params),
response);
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({
address: "YOUR_CLUSTER_ENDPOINT",
});
const analyzer_params = {
tokenizer: {
type: "lindera",
dict_kind: "ko-dic",
filter: [
{
kind: "korean_stop_tags",
tags: [
"SP",
"SSC",
"SSO",
"SC",
"SE",
"SF",
"JKS",
"JKC",
"JKG",
"JKO",
"JKB",
"JKV",
"JKQ",
"JX",
"JC",
"UNK",
"EP",
"ETM",
],
},
],
},
};
const sample_text = "서울에서 맛있는 음식을 먹었습니다";
const result = await client.runAnalyzer({
analyzer_params: analyzer_params,
text: sample_text,
});
console.log("Analyzer output:", result);
export CLUSTER_ENDPOINT="YOUR_CLUSTER_ENDPOINT"
export TOKEN="YOUR_CLUSTER_TOKEN"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/common/run_analyzer" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"analyzerParams": "{\"tokenizer\":{\"type\":\"lindera\",\"dict_kind\":\"ko-dic\",\"filter\":[{\"kind\":\"korean_stop_tags\",\"tags\":[\"SP\",\"SSC\",\"SSO\",\"SC\",\"SE\",\"SF\",\"JKS\",\"JKC\",\"JKG\",\"JKO\",\"JKB\",\"JKV\",\"JKQ\",\"JX\",\"JC\",\"UNK\",\"EP\",\"ETM\"]}]}}",
"text": ["서울에서 맛있는 음식을 먹었습니다"]
}'
期待される出力:
['서울', '맛있', '음식', '먹', '습니다']
korean_stop_tags を使用しない場合、出力には 에서(〜で)、는(主題標識)、을(目的語標識)などの助詞が含まれます。これらは通常、検索には役立ちません。
日本語の例
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
from pymilvus import MilvusClient
client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT")
analyzer_params = {
"tokenizer": {
"type": "lindera",
"dict_kind": "ipadic",
"filter": [
{
"kind": "japanese_stop_tags",
"tags": ["接続詞", "助詞,格助詞", "助詞,格助詞,一般", "助詞,格助詞,引用", "助詞,格助詞,連語", "助詞,係助詞", "助詞,終助詞", "助詞,接続助詞", "助詞,特殊", "助詞,副助詞", "助詞,副助詞/並立助詞/終助詞", "助詞,連体化", "助詞,副詞化", "助詞,並立助詞", "助動詞", "記号,一般", "記号,読点", "記号,句点", "記号,空白", "記号,括弧閉", "記号,括弧開", "その他,間投", "フィラー", "非言語音"]
}
]
}
}
# Sample Japanese text: "東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です"
sample_text = "東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です"
result = client.run_analyzer(sample_text, analyzer_params)
print("Analyzer output:", result)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.vector.request.RunAnalyzerReq;
import io.milvus.v2.service.vector.response.RunAnalyzerResp;
import java.util.*;
ConnectConfig config = ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.build();
MilvusClientV2 client = new MilvusClientV2(config);
Map<String, Object> analyzerParams = new HashMap<>();
analyzerParams.put("tokenizer", new HashMap<String, Object>() {{
put("type", "lindera");
put("dict_kind", "ipadic");
put("filter", Arrays.asList(
new HashMap<String, Object>() {{
put("kind", "japanese_stop_tags");
put("tags", Arrays.asList(
"接続詞", "助詞,格助詞", "助詞,格助詞,一般", "助詞,格助詞,引用", "助詞,格助詞,連語", "助詞,係助詞", "助詞,終助詞", "助詞,接続助詞", "助詞,特殊", "助詞,副助詞", "助詞,副助詞/並立助詞/終助詞", "助詞,連体化", "助詞,副詞化", "助詞,並立助詞", "助動詞", "記号,一般", "記号,読点", "記号,句点", "記号,空白", "記号,括弧閉", "記号,括弧開", "その他,間投", "フィラー", "非言語音"
));
}}
));
}});
List<String> texts = new ArrayList<>();
texts.add("東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です");
RunAnalyzerResp resp = client.runAnalyzer(RunAnalyzerReq.builder()
.texts(texts)
.analyzerParams(analyzerParams)
.build());
List<RunAnalyzerResp.AnalyzerResult> results = resp.getResults();
import (
"context"
"fmt"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
ctx := context.Background()
client, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: "YOUR_CLUSTER_ENDPOINT",
APIKey: "YOUR_CLUSTER_TOKEN",
})
if err != nil {
fmt.Println(err.Error())
// handle error
}
analyzerParams := map[string]interface{}{
"tokenizer": map[string]interface{}{
"type": "lindera",
"dict_kind": "ipadic",
"filter": []interface{}{
map[string]interface{}{
"kind": "japanese_stop_tags",
"tags": []string{
"接続詞", "助詞,格助詞", "助詞,格助詞,一般", "助詞,格助詞,引用", "助詞,格助詞,連語", "助詞,係助詞", "助詞,終助詞", "助詞,接続助詞", "助詞,特殊", "助詞,副助詞", "助詞,副助詞/並立助詞/終助詞", "助詞,連体化", "助詞,副詞化", "助詞,並立助詞", "助動詞", "記号,一般", "記号,読点", "記号,句点", "記号,空白", "記号,括弧閉", "記号,括弧開", "その他,間投", "フィラー", "非言語音",
},
},
},
},
}
texts := []string{"東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です"}
option := milvusclient.NewRunAnalyzerOption(texts...).
WithAnalyzerParams(analyzerParams)
_, err = client.RunAnalyzer(ctx, option)
if err != nil {
fmt.Println(err.Error())
// handle error
}
use milvus::v2::prelude::*;
use serde_json::json;
let config = ConnectConfig::new().uri("YOUR_CLUSTER_ENDPOINT");
let client = ClientV2::new(&config).await?;
let analyzer_params = json!({
"tokenizer": {
"type": "lindera",
"dict_kind": "ipadic",
"filter": [
{
"kind": "japanese_stop_tags",
"tags": ["接続詞", "助詞,格助詞", "助詞,格助詞,一般", "助詞,格助詞,引用", "助詞,格助詞,連語", "助詞,係助詞", "助詞,終助詞", "助詞,接続助詞", "助詞,特殊", "助詞,副助詞", "助詞,副助詞/並立助詞/終助詞", "助詞,連体化", "助詞,副詞化", "助詞,並立助詞", "助動詞", "記号,一般", "記号,読点", "記号,句点", "記号,空白", "記号,括弧閉", "記号,括弧開", "その他,間投", "フィラー", "非言語音"]
}
]
}
});
let run_analyzer_req = RunAnalyzerRequest::builder()
.texts(vec!["東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です"])
.analyzer_params(analyzer_params)
.build()?;
let res = client.run_analyzer(run_analyzer_req).await?;
println!("{:?}", res.results());
#include "milvus/MilvusClientV2.h"
#include <iostream>
auto client = milvus::MilvusClientV2::Create();
milvus::ConnectParam connect_param{"YOUR_CLUSTER_ENDPOINT"};
auto status = client->Connect(connect_param);
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
nlohmann::json analyzer_params = {
{"tokenizer", {
{"type", "lindera"},
{"dict_kind", "ipadic"},
{"filter", {{
{"kind", "japanese_stop_tags"},
{"tags", {"接続詞", "助詞,格助詞", "助詞,格助詞,一般", "助詞,格助詞,引用", "助詞,格助詞,連語", "助詞,係助詞", "助詞,終助詞", "助詞,接続助詞", "助詞,特殊", "助詞,副助詞", "助詞,副助詞/並立助詞/終助詞", "助詞,連体化", "助詞,副詞化", "助詞,並立助詞", "助動詞", "記号,一般", "記号,読点", "記号,句点", "記号,空白", "記号,括弧閉", "記号,括弧開", "その他,間投", "フィラー", "非言語音"}}
}}}
}}
};
milvus::RunAnalyzerResponse response;
status = client->RunAnalyzer(milvus::RunAnalyzerRequest()
.WithTexts({"東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です"})
.WithAnalyzerParams(analyzer_params),
response);
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({
address: "YOUR_CLUSTER_ENDPOINT",
});
const analyzer_params = {
tokenizer: {
type: "lindera",
dict_kind: "ipadic",
filter: [
{
kind: "japanese_stop_tags",
tags: ["接続詞", "助詞,格助詞", "助詞,格助詞,一般", "助詞,格助詞,引用", "助詞,格助詞,連語", "助詞,係助詞", "助詞,終助詞", "助詞,接続助詞", "助詞,特殊", "助詞,副助詞", "助詞,副助詞/並立助詞/終助詞", "助詞,連体化", "助詞,副詞化", "助詞,並立助詞", "助動詞", "記号,一般", "記号,読点", "記号,句点", "記号,空白", "記号,括弧閉", "記号,括弧開", "その他,間投", "フィラー", "非言語音"],
},
],
},
};
const sample_text = "東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です";
const result = await client.runAnalyzer({
analyzer_params: analyzer_params,
text: sample_text,
});
console.log("Analyzer output:", result);
export CLUSTER_ENDPOINT="YOUR_CLUSTER_ENDPOINT"
export TOKEN="YOUR_CLUSTER_TOKEN"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/common/run_analyzer" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"analyzerParams": "{\"tokenizer\":{\"type\":\"lindera\",\"dict_kind\":\"ipadic\",\"filter\":[{\"kind\":\"japanese_stop_tags\",\"tags\":[\"接続詞\",\"助詞,格助詞\",\"助詞,格助詞,一般\",\"助詞,格助詞,引用\",\"助詞,格助詞,連語\",\"助詞,係助詞\",\"助詞,終助詞\",\"助詞,接続助詞\",\"助詞,特殊\",\"助詞,副助詞\",\"助詞,副助詞/並立助詞/終助詞\",\"助詞,連体化\",\"助詞,副詞化\",\"助詞,並立助詞\",\"助動詞\",\"記号,一般\",\"記号,読点\",\"記号,句点\",\"記号,空白\",\"記号,括弧閉\",\"記号,括弧開\",\"その他,間投\",\"フィラー\",\"非言語音\"]}]}}",
"text": ["東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です"]
}'
期待される出力:
['東京', 'スカイ', 'ツリー', '最寄り駅', 'とう', 'きょう', 'スカイ', 'ツリー', '駅']
japanese_stop_tags を使用しない場合、出力には の(所有)、は(主題標識)、です(コピュラ)などの助詞が含まれます。