#大数据/ES #经验 #方案架构
ES检索PDF/Word等格式文件方案
插件安装
ES有文档预处理插件,但是7.x版本默认发版包不包含这个ingest attachment plugin
。
通过摄取附件插件,Elasticsearch 可以使用 Apache 文本提取库 Tika 提取常见格式的文件附件(如 PPT、XLS 和 PDF)。
源字段必须是 base64 编码的二进制文件。如果不想承担在 base64 之间来回转换的开销,可以使用 CBOR 格式而不是 JSON 格式,并将字段指定为字节数组而不是字符串表示。这样处理器就会跳过 base64 解码。
在线安装
以下命令直接联网下载插件并安装
sudo bin/elasticsearch-plugin install ingest-attachment
离线安装
官网有说:This plugin can be downloaded for offline install from https://artifacts.elastic.co/downloads/elasticsearch-plugins/ingest-attachment/ingest-attachment-7.3.2.zip.
./bin/elasticsearch-plugin install file:///opt/ingest-attachment-7.3.2.zip
注意:集群的所有ES服务实例都要安装这个插件!
最后,重启ElasticSearch全部服务。
构建管道
在Kibana中执行:
PUT /_ingest/pipeline/attachment
{"description": "Extract attachment information","processors": [{"attachment": {"field": "content","ignore_missing": true}},{"remove": {"field": "content"}}]
}
上述命令返回:
{"acknowledged" : true
}
在attachment
中指定要预处理的字段为content
,所以写入Elasticsearch
时需要将文档内容放在content
字段。
建立文档结构映射
为了提高搜索的效果,我们需要建立文档结构映射来定义文本文件通过预处理器上传后以何种形式存储。
使用PUT指令先创建一个docwrite
的索引,用于接收测试数据。
首先,我们需要保证ES已经有中文分词器ik插件,这里不再赘述。
PUT /docwrite
{"mappings": {"properties": {"id":{"type": "keyword"},"name":{"type": "text","analyzer": "ik_max_word"},"type":{"type": "keyword"},"attachment": {"properties": {"content":{"type": "text","analyzer": "ik_smart"}}}}}
}
上述请求返回:
{"acknowledged" : true,"shards_acknowledged" : true,"index" : "docwrite"
}
attachment
这个字段是attachment
命名pipeline
抽取文档附件中文本后自动附加的字段。这是一个嵌套字段,其包含多个子字段,包括抽取文本 content
和一些文档信息元数据。
测试
如文章开头所述,因ElasticSearch
是基于JSON
格式的文档数据库,所以附件文档在插入ElasticSearch
之前必须进行Base64
编码。先通过下面的网站将一个pdf文件转化为Base64
的文本:
这是一个在线PDF转base64的小网站,有广告,有可能不可用:https://www.toolfk.com/tools/pdf-to-base64.html
使用上述网站只能转换点小文件(也可能是浏览器的问题),我转了一个10页的PPT后页面无响应,无法拷贝结果。
随后我转了一个更小PDF,可复制结果,发现字符数也有41万之多。
注意,ES默认限制一个字段只能索引最大10万个字符,因此需要修改前面的管道参数(改为100万),也可改为无限制但最好不要这样做:
PUT /_ingest/pipeline/attachment
{"description": "Extract attachment information","processors": [{"attachment": {"field": "content","indexed_chars":1000000,"ignore_missing": true}},{"remove": {"field": "content"}}]
}
# 这里,重新创建了一下索引
写入文档内容并索引
POST /docwrite/_doc?pipeline=attachment
{"name":"性能分析排查思路","type":"pdf","url":"http://文件存储地址:8080/xxx/docs/raw/master/性能分析与内存问题排查思考.pdf","content":"很长很长的base64内容粘贴到这了"
}
查询测试
GET /docwrite/_search
{"query": {"match": {"attachment.content": {"query": "内存泄漏","analyzer": "ik_smart"}}}
}
返回:能够查到1条结果(但目前只有这一条结果)。
作为对比,我们将本文档也转码为Base64格式上传上去。
然后继续搜索"内存泄漏"只出现了第一篇文档,而搜Base64
则只出现了第二篇文档。
过程中解决了ES请求体过大和Kibana无法发送大请求的问题!(对于生产环境是必须的!)
结论
方案可行
后期,后端只需要使用Java API即可实现程序化转码PDF并上传。
建设思路
使用git hook实时监控触发,或者直接简单使用定时任务从文件源下载pdf、word、md等格式的文档,使用java将文档内容转成Base64格式,仿照上面的思路方法写入ES,就可实现全文搜索了,搜索到的文档可以返回文档的在线下载地址,可以直接打开或下载,完成闭环。