学习日志 211230 elasticsearch同义词 从java端发起调用
# 211230
## 继续搞同义词字典上传
- 上传文件给pod有以下几种方式
- 使用configMap
- 可共享 有大小限制 最多3M
- 使用pvc
- 不可共享 扩容的话需要手工对扩出来的pod再上传
- 使用initContainers指令做curl
- 不需要重复操作
- 需要一个源
- 提前做好docker image
- 不需要重复操作
- 比较麻烦
- 综上 我们尝试一下initContainers
- 源用内部nginx
- 内部nginx上的文件 使用pvc cp的方式
- 搞一个内部nginx
- 参考 https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/
- 不写cpu和内存 看一下默认是多少
- 全是0
- port-forward 80 出错
- 使用 `kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm /bin/sh`
- 创建dns检查环境
- 使用 nslookup mycluster-nginx-0.mycluster-nginx
- 发现DNS不通 怀疑service有问题
- 检查service发现 service的selector写错了
- 修复后重新apply -f
- 重新port-forward
- 检查localhost:80 可以访问
- 上传文件
- 采用 kubectl cp指令
- `kubectl cp .\synonym\synonyms.json mycluster-nginx-0:/usr/share/nginx/html`
- 其中 /usr/share/nginx/html 目录是nginx读取的源目录
- 也是pvc 挂载的目录
- 测试 http://localhost/synonyms.json
- 让elasticsearch使用initContainers 将该文件copy到自己的运行环境
- 指令格式
- 前面的 sh -c | 不变
- 后面指令为
- `mkdir /usr/share/elasticsearch/config/dictionaries && curl -o /usr/share/elasticsearch/config/dictionaries/synonyms.json http://mycluster-nginx-0.mycluster-nginx/synonyms.json`
- 注意需要mkdir 不然dictionaries目录不存在
- elasticsearch报格式不对
- 修改同义词词典的格式
- 不需要json格式
```
s(100001740,1,'entity',n,1,11).
s(100001930,1,'physical entity',n,1,0).
s(100002137,1,'abstraction',n,6,0).
```
- 重新上传到nginx上
- 修改es的k8s描述文件中initContainers的文件名
- 测试
```
PUT /test_index
{
"settings": {
"index": {
"analysis": {
"analyzer": {
"synonym": {
"tokenizer": "whitespace",
"filter": [ "synonym" ]
}
},
"filter": {
"synonym": {
"type": "synonym",
"format": "wordnet",
"synonyms_path": "dictionaries/synonyms.txt"
}
}
}
}
}
}
POST /test_index/_analyze
{
"analyzer": "synonym",
"text":"person"
}
```
- 结果 person 在wordnet中有6个同义词
## 应用分析器到索引
- 我们自己的`test_doc`原始字段只有`id``doc`
- 为doc字段建一个subfield叫做`doc.synonym`
- 先建对应的自定义analyzer
- tokenizer standard
- filter
- lowercase
- asciifolding
- snowball
- synonym
- 构建期采用synonym的filter, 搜索时则采用synonym_graph
- 由于不能针对已有index做更新(非runtime字段)
- 所以删除旧索引重建, 完整的定义如下
```
PUT /test_doc
{
"mappings" : {
"dynamic" : "runtime",
"properties" : {
"doc" : {
"type" : "text",
"fields" : {
"synonym" : {
"type" : "text",
"analyzer":"my_synonym",
"search_analyzer":"my_search_synonym"
}
}
},
"id" : {
"type" : "long"
}
}
},
"settings": {
"index": {
"analysis": {
"analyzer": {
"my_synonym": {
"tokenizer": "standard",
"filter": [
"lowercase",
"asciifolding",
"snowball",
"synonym" ]
},
"my_search_synonym": {
"tokenizer": "standard",
"filter": [
"lowercase",
"asciifolding",
"snowball",
"synonym_graph" ]
}
},
"filter": {
"synonym": {
"type": "synonym",
"format": "wordnet",
"synonyms_path": "dictionaries/synonyms.txt"
},
"synonym_graph": {
"type": "synonym_graph",
"format": "wordnet",
"synonyms_path": "dictionaries/synonyms.txt"
}
}
}
}
}
}
```
- 测试
```
PUT /test_doc/_doc/1
{
"id": 1,
"doc": "test doc 1 v2 someone"
}
GET /test_doc/_search
{
"query": {
"match": {
"doc.synonym": "person"
}
}
}
```
- 注意如果是针对 doc字段(不是doc.synonym) 就没有同义词功能
# java应用访问elasticsearch
- 解决一下secret的问题
- 即elasticsearch的用户名和密码
- 参考 https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets
- 在volumes下增加一个节点
```
- name: elastic-user-volume
secret:
secretName: quickstart-es-elastic-user
```
- 在pod的volumeMounts下增加一个节点
```
- name: elastic-user-volume
mountPath: /app/secret-elastic-user
readOnly: true
```
- 结果
- pod增加了一个/app/secret-elastic-user目录
- 里面有一个名为 elastic 的文本文件
- 内容是密码
- 用spring boot properties读取该密码
- 也可以把secret映射成env 环境变量
- 采用自定义service的方法, 使用InitializingBean接口, 在afterPropertiesSet方法中主动读取密码
- 直接采用java 11的httpclient发起对elasticsearch集群的请求
- elastic search的原配客户端用的不是java 11的http client
- 怕有冲突
- 测试环境问题
- 使用port-forward
- 服务名 service/quickstart-es-http
- 端口 9200
- 根据环境变量env决定使用测试的localhost还是集群内部域名
- 集群内部域名为 quickstart-es-http:9200
- 构造请求串的问题
- 不使用elasticsearch的客户端 所以自己做json字符串
- 使用String.format替换 因为 %s 不容易和json数据冲突
- 未考虑注入问题 线上使用必须加escape
- 用户名密码如何传入的问题
- 参考 https://www.elastic.co/guide/en/elasticsearch/reference/current/http-clients.html#:~:text=The%20Elasticsearch%20security%20features%20work%20with%20standard%20HTTP,be%20sent%20with%20every%20request%3A%20Authorization%3A%20Basic%20%3CTOKEN%3E
- 其实就是加个header 名字 Authorization
- 取值 Basic <TOKEN>
- 其中 <TOKEN> 是 base64(USERNAME:PASSWORD)
- 报错没响应 需要走https协议
- url改为https开头
- 报错自签名证书问题
- 参考 https://stackoverflow.com/questions/1201048/allowing-java-to-use-an-untrusted-certificate-for-ssl-https-connection/1201102#1201102
- 关掉自签名证书
- 报错域名校验问题
- 参考 https://stackoverflow.com/questions/52988677/allow-insecure-https-connection-for-java-jdk-11-httpclient
- 关掉域名校验
- Postman直接测elasticsearch
- 提前验证用户名密码验证的问题
- postman关掉ssl校验
- 因为9200已经port-forward出来了, 所以直接往这个地址发即可
- 用异步接口 加try catch exception
- 结果
- 测试环境通过
- 后续问题 TODO
- 返回数据解析
- 发布验证