Lindera
lindera 分词器执行基于词典的形态素分析,专为日语和韩语设计——这两种语言的词汇之间没有空格分隔,且语法标记(助词)直接附着在词汇上。
中文用户:虽然 lindera 通过 cc-cedict 词典支持中文,但我们推荐使用 [jieba](jieba-tokenizer.md) 分词器。Jieba 专为中文分词设计,能提供更好的效果。
概述
日语和韩语都是黏着语:语法标记(助词)直接附着在名词上,形成大量组合。例如:
语言 | 词根 |
| = 组合形式 | 含义 |
|---|---|---|---|---|
Korean | 서울 (Seoul) | 에서 | 서울에서 | 在首尔 |
Japanese | 東京 (Tokyo) | に | 東京に | 向东京 |
lindera 分词器的处理流程:
-
分词:将文本拆分为独立的词素(词汇和助词)
-
词性标注:为每个 token 标注词典中的词性(POS)信息
-
过滤:移除不需要的 token(如助词、标点)
这种"先分词,再按词性过滤"的两阶段处理流程,使用户能够精确控制哪些 token 被索引用于搜索。
配置
要配置使用 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": ["서울에서 맛있는 음식을 먹었습니다"]
}'
参数名称 | 参数描述 |
|---|---|
| 分词器类型,在使用 Lindera 分词器时,该值为 |
| 作为参考词表的字典。取值范围如下:
|
| 分词后应用的分词器级别过滤器列表。每个过滤器是一个包含以下字段的对象:
|
在定义了 analyzer_params 后,您可以在定义 Collection Schema 时将其应用到 VARCHAR 类型的字段上。Zilliz Cloud 将会根据 Analyzer 的设置对该字段的内容进行分词和过滤。更多详情,可参考使用示例。
使用示例
在完成 Analyzer 配置后,您可以使用 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": ["東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です"]
}'
预期输出:
['東京', 'スカイ', 'ツリー', '最寄り駅', 'とう', 'きょう', 'スカイ', 'ツリー', '駅']