我希望在Kubernetes上的Elasticsearch中有一个用户字典
首先
在我的Kubernetes上的家用elasticsearch中,我使用了由elastic提供的kuromoji插件。
由于这个插件的词典很旧,例如”云”这样的词完全不支持,所以我在用户词典中进行了对应。
前提条件
以下是我們在這篇文章中建立的環境。我們每次都會更新elasticsearch到最新版本。
用户词典的定义 de
考虑到以更类似于Kubernetes的方式进行智能实现,我们决定使用ConfigMap来管理字典文件。通过在ConfigMap中将目录挂载到volumeMount,即使不重新启动服务,也可以动态地将其反映到Pod中。此外,与持久存储相比,使用起来更加方便,并且可以让多个Pod引用相同的内容。
创建ConfigMap
可以从Pod中引用的文件名被设定为”userdict.txt”。
需要注意的是,ConfigMap的大小默认限制为3MB。我们稍微调查了一下,虽然可以进行更改,但这可能会对整个Kubernetes的性能产生影响。因此,如果用户词典的注册词非常多的话,最好准备持久性存储作为解决方案。
apiVersion: v1
data:
userdict.txt: |
東京スカイツリー,東京 スカイツリー,トウキョウ スカイツリー,カスタム名詞
kind: ConfigMap
metadata:
name: elastic-dict
namespace: elastic
# kubectl apply -f elastic-dict.yaml
将数据文件挂载到elasticsearch容器中。
Elasticsearch的前提条件是以下文章中的内容。编辑这里的statefulset的yaml文件。
在将卷挂载到容器时,请使用指定目录进行挂载。
如果使用subPath将单个文件挂载到现有目录中,即使更新了ConfigMap(用户字典),更新内容也不会反映在Pod内部。
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch
namespace: elastic
spec:
selector:
matchLabels:
app: elasticsearch
serviceName: "elasticsearch"
replicas: 3
template:
metadata:
labels:
app: elasticsearch
spec:
initContainers:
# 略
containers:
- name: elasticsearch
image: docker.elastic.co/elasticsearch/elasticsearch:7.12.1
# 略
volumeMounts:
# volumeMountsにelastic-dictをmountする定義を追記
- name: elastic-dict
mountPath: /usr/share/elasticsearch/config/dict
volumes:
# volumesにelastic-dictのConfigMapを追記
- name: elastic-dict
configMap:
name: elastic-dict
# 略
由于害怕,所以先完全停止(使用delete),然后再应用。(应用也没有意义.)
# kubectl delete -f elasticsearch-sts-sec.yaml
# kubectl apply -f elasticsearch-sts-sec.yaml
更新用户词典
我会确认一下能否正确地将其挂载到Pod上。
# kubectl exec -it elasticsearch-0 -n elastic -- cat /usr/share/elasticsearch/config/dict/userdict.txt
東京スカイツリー,東京 スカイツリー,トウキョウ スカイツリー,カスタム名詞
由于ConfigMap资源,可以使用kubectl edit命令进行更新。
# kubectl edit configmap/elastic-dict -n elastic
进入vi编辑界面,在yaml文件中添加单词。
使用自定义名词将”云”加入。
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
userdict.txt: |
東京スカイツリー,東京 スカイツリー,トウキョウ スカイツリー,カスタム名詞
クラウド,クラウド,クラウド,カスタム名詞
kind: ConfigMap
metadata:
creationTimestamp: "2021-03-25T14:35:02Z"
name: elastic-dict
namespace: elastic
resourceVersion: "79233490"
uid: bf3f976a-d279-41ec-bd1c-b4f264fd5b16
当您输入「:wq」并保存退出时,将显示消息「configmap/elastic-dict 已编辑」。
我会检查 Pod 是否已经被修改。(在 Kubernetes 的 Pod 上最多需要 120 秒才能反映出来。)
# kubectl exec -it elasticsearch-0 -n elastic -- cat /usr/share/elasticsearch/config/dict/userdict.txt
東京スカイツリー,東京 スカイツリー,トウキョウ スカイツリー,カスタム名詞
クラウド,クラウド,クラウド,カスタム名詞
如果确认从Pod获取到用户词典的更新,为了重新读取用户词典,将关闭索引然后再次打开。
# curl -XPOST -u elastic http://elasticsearch:9200/testindex/_close?pretty
# curl -XPOST -u elastic http://elasticsearch:9200/testindex/_open?pretty
如果您已经拥有具有解析过的字段的文档,并且想要使用更新的用户词典重新进行解析,则可以使用”_update_by_query”指定所有文档。
# curl -H 'Content-Type: application/json' -XPOST -u elastic http://elasticsearch:9200/testindex/_update_by_query?conflicts=proceed\&pretty -d '
{
"query": {
"match_all": {}
}
}'
我已经进行到这一步了,但是我意识到使用kubernetes的API来更新用户字典会很难与外部工具协调。
不过,我认为用户字典的”更新”频率较低,所以我打算用这种方法来管理。
额外的 – 在分析器中确认
我正在创建并验证一个具有以下用户词典设置的索引,尽管其记录可能有前后不一。
# curl -H 'Content-Type: application/json' -XPUT -u elastic http://elasticsearch:9200/testindex?pretty -d '
{
"settings": {
"index": {
"analysis": {
"tokenizer": {
"custom_tokenizer": {
"type": "kuromoji_tokenizer",
"mode": "search",
"discard_punctuation": "true",
"user_dictionary": "dict/userdict.txt"
}
},
"analyzer": {
"custom_analyzer": {
"type": "custom",
"tokenizer": "custom_tokenizer"
}
}
}
}
}
}'
用分析器进行确认的命令如下所示。
# curl -H 'Content-Type: application/json' -XPOST -u elastic http://elasticsearch:9200/testindex/_analyze?pretty -d '
{
"analyzer": "custom_analyzer",
"text": ["東京スカイツリーの上部にクラウドが"]
}'
结果如下。
{
"tokens" : [
{
"token" : "東京",
"start_offset" : 0,
"end_offset" : 2,
"type" : "word",
"position" : 0
},
{
"token" : "スカイツリー",
"start_offset" : 2,
"end_offset" : 8,
"type" : "word",
"position" : 1
},
{
"token" : "の",
"start_offset" : 8,
"end_offset" : 9,
"type" : "word",
"position" : 2
},
{
"token" : "上部",
"start_offset" : 9,
"end_offset" : 11,
"type" : "word",
"position" : 3
},
{
"token" : "に",
"start_offset" : 11,
"end_offset" : 12,
"type" : "word",
"position" : 4
},
{
"token" : "クラウド",
"start_offset" : 12,
"end_offset" : 16,
"type" : "word",
"position" : 5
},
{
"token" : "が",
"start_offset" : 16,
"end_offset" : 17,
"type" : "word",
"position" : 6
}
]
}
正确地在云端进行了分析。
最后
我构建过后发现,经常更新用户词典的目的不太适合。
而且,当ConfigMap更新较慢时,很难在下一个操作的索引中反映出来。
不过,虽然有3MB的限制,但在kubernetes内部无需”拥有文件”这一点对我来说是一个有吸引力的操作方式。
偶尔回应一些在Elasticsearch上遇到困惑的人们的吐槽,非常感谢Ohtani先生!
※本文及与Ohtani先生无关。