当前位置: 代码网 > it编程>网页制作>网页播放器 > ElasticSearch 实现 全文检索 支持(PDF、TXT、Word、HTML等文件)通过 ingest-attachment 插件实现 文档的检索

ElasticSearch 实现 全文检索 支持(PDF、TXT、Word、HTML等文件)通过 ingest-attachment 插件实现 文档的检索

2024年08月03日 网页播放器 我要评论
Attachment 插件是 Elasticsearch 中的一种插件,允许将各种二进制文件(如PDF、Word文档等)以及它们的内容索引到 Elasticsearch 中。插件使用 Apache Tika 库来解析和提取二进制文件的内容。通过使用 Attachment 插件,可以轻松地在 Elasticsearch 中建立全文搜索功能,而无需事先转换二进制文件为文本。

一、attachment 介绍

attachment 插件是 elasticsearch 中的一种插件,允许将各种二进制文件(如pdf、word文档等)以及它们的内容索引到 elasticsearch 中。插件使用 apache tika 库来解析和提取二进制文件的内容。通过使用 attachment 插件,可以轻松地在 elasticsearch 中建立全文搜索功能,而无需事先转换二进制文件为文本。

优点:

缺点:

二、初始化 ingest-attachment

1、windows安装

 1、先在es的bin目录下执行命令 安装 ngest-attachment插件

elasticsearch-plugin install ingest-attachment

作者已经安装过了 所以不能重复安装,插件下载过程中会出现

2、liunx安装 

通过官网下载,找到对应的版本号:attachment下载网站

3、小结

安装完成后需要重新启动es

接下来我们需要创建一个关于ingest-attachment的文本抽取管道

put /_ingest/pipeline/attachment
{
    "description": "extract attachment information",
    "processors": [
        {
            "attachment": {
                "field": "content",
                "ignore_missing": true
            }
        },
        {
            "remove": {
                "field": "content"
            }
        }
    ]
}

后续我们的文件需要base64后储存到 attachment.content 索引字段中

三、如何应用?

1、通过命令语句简易检索

# 创建一个es 索引 并且添加一些测试数据

post /pdf_data/_doc?pretty
{

  "id": "3",

  "name": "面试题文件1.pdf",

  "age": 18,

  "type": "file",

  "money": 1111,

  "createby": "阿杰",

  "createtime": "2022-11-03t10:41:51.851z",

  "attachment": {

    "content": "面试官:如何保证消息不被重复消费啊?如何保证消费的时候是幂等的啊?kafka、activemq、rabbitmq、rocketmq 都有什么区别,以及适合哪些场景?",

    "date": "2022-11-02t10:41:51.851z",

    "language": "en"

  }
}

# 通过插入的文档内容为条件进行检索

# 简单 单条件查询 文档内容检索
get /pdf_data/_search
{
  "query": {
    "match": {
      "attachment.content": "面试官:如何保证消息不被重复消费啊?如何保证消费的时候是幂等的啊?"
    }
  }
}

2、整合java代码实现es通过ingest-attachment进行全文检索

 1、首先将文件转为base64进行es数据插入

/**
     * 将文件 文档信息储存到数据中
     * @param file
     * @return
     */
    @postmapping("/insertfile")
    @apioperation(value="创建索引es-传入es索引-传入文件", notes="创建索引es-传入es索引-传入文件")
    public indexresponse insertfile(@requestattribute("file") multipartfile file,@requestparam("indexname")string indexname){
        fileobj fileobj = new fileobj();
        fileobj.setid(string.valueof(system.currenttimemillis()));
        fileobj.setname(file.getoriginalfilename());
        fileobj.settype(file.getname().substring(file.getname().lastindexof(".") + 1));
        fileobj.setcreateby(randomnamegenerator.generaterandomname());
        fileobj.setcreatetime(string.valueof(system.currenttimemillis()));
        fileobj.setage(randomnamegenerator.getage());
        fileobj.setmoney(randomnamegenerator.getmoney());
        // 文件转base64
        byte[] bytes = new byte[0];
        try {
            bytes = file.getbytes();
            //将文件内容转化为base64编码
            string base64 = base64.getencoder().encodetostring(bytes);
            fileobj.setcontent(base64);

           indexresponse indexresponse=  elasticsearchutil.upload(fileobj,indexname);
            if (0==indexresponse.status().getstatus()){
                // 索引创建并插入数据成功
                system.out.println("索引创建并插入数据成功");
            }
            return indexresponse;

        } catch (exception e) {
            e.printstacktrace();
        }
        return null;
    }

 2、创建索引、插入数据,并且将文档数据抽取到管道中

    @autowired
    private resthighlevelclient resthighlevelclient;

    private  static  resthighlevelclient levelclient;

    @postconstruct
    public void initclient() {
        levelclient = this.resthighlevelclient;
    }

/**
     * 创建索引并插入数据
     * @param file
     * @param indexname
     * @return
     * @throws ioexception
     */
    public static indexresponse upload(fileobj file,string indexname) throws ioexception {
        // todo 创建前需要判断当前文档是否已经存在
        if (!isindexexist(indexname)) {
            createindexrequest request = new createindexrequest(indexname);
        // 如果需要ik分词器就添加配置,不需要就注释掉 
            // 添加 ik 分词器设置  ik_max_word
//            request.settings(settings.builder()
//                    .put("index.analysis.analyzer.default.type", "ik_max_word")
//                    .put("index.analysis.analyzer.default.use_smart", "true")
//            );
            
            // 添加 ik 分词器设置 ik_smart 
            request.settings(settings.builder()
                    .put("index.analysis.analyzer.default.type", "ik_smart")
            );
            createindexresponse response = levelclient.indices().create(request, requestoptions.default);
            log.info("执行建立成功?" + response.isacknowledged());
        }
        indexrequest indexrequest = new indexrequest(indexname);
        //上传同时,使用attachment pipline进行提取文件
        indexrequest.source(json.tojsonstring(file), xcontenttype.json);
        indexrequest.setpipeline("attachment");
        indexresponse indexresponse= levelclient.index(indexrequest,requestoptions.default);
        system.out.println(indexresponse);
        return indexresponse;
    }

  3、其他代码补充

   es config 配置类 

/**
 * es配置类
 * author: 阿杰
 */
@configuration
public class elasticsearchclientconfig {

    /**
     * es 地址:127.0.0.1:9200
     */
    @value("${es.ip}")
    private string hostname;

    @bean
    public resthighlevelclient resthighlevelclient() {
        string[] points = hostname.split(",");
        httphost[] httphosts = new httphost[points.length];
        for (int i = 0; i < points.length; i++) {
            string point = points[i];
            httphosts[i] = new httphost(point.split(":")[0], integer.parseint(point.split(":")[1]), "http");
        }
        resthighlevelclient client = new resthighlevelclient(
                restclient.builder(httphosts));
        return client;
    }

    @bean
    public elasticsearchutil elasticsearchutil() {
        return new elasticsearchutil();
    }


}

数据插入使用的实体类

/**
 * author: 阿杰
 */
@data
public class fileobj {
    /**
     * 用于存储文件id
     */
    string id;
    /**
     * 文件名
     */
    string name;
    /**
     * 文件的type,pdf,word,or txt
     */
    string type;
    /**
     * 数据插入时间
     */
    string createtime;
    /**
     * 当前数据所属人员
     */
    string createby;

    /**
     * 当前数据所属人员的年龄
     */
    int age;

    /**
     * 当前数据所属人员的资产
     */
    int money;

    /**
     * 文件转化成base64编码后所有的内容。
     */
    string content;
}

 四、补充一点

querybuilders.matchphrasequery 和 querybuilders.matchquery 都是 elasticsearch java api 中用于构建查询的方法,它们在使用上有以下区别:

  1. 匹配方式不同

    • matchphrasequery 是短语匹配查询,它会将输入的文本作为一个短语进行匹配。短语匹配要求查询的字段包含输入的短语且顺序一致。
    • matchquery 是多词项匹配查询,它会将输入的文本根据分词器进行分词,并对分词结果进行匹配。匹配结果是包含输入的任意词项的文档。
  2. 查询方式不同

    • matchphrasequery 使用短语查询方式,它会对输入的短语进行关键词匹配,精确匹配所有词项并保留顺序。
    • matchquery 使用与布尔查询相似的查询方式,它会将输入的文本进行分词,并生成与分词结果匹配的查询条件。
  3. 分词不同

    • matchphrasequery 不会对输入的短语进行分词,而是将输入的短语作为整个短语进行匹配。
    • matchquery 会对输入的文本进行分词,并将分词结果作为关键词进行匹配。

下面是使用示例:

import org.elasticsearch.index.query.querybuilders;
import org.elasticsearch.index.query.querybuilder;

// 使用 matchphrasequery 进行短语匹配查询
querybuilder matchphrasequerybuilder = querybuilders.matchphrasequery("fieldname", "input phrase");

// 使用 matchquery 进行多词项匹配查询
querybuilder matchquerybuilder = querybuilders.matchquery("fieldname", "input text");

根据实际需求,选择合适的查询方式来构建你的查询条件。如果需要精确匹配全部词项且保留顺序,使用 matchphrasequery;如果需要简单的多词项匹配,使用 matchquery

完整代码可通过: 

制作不易,给个小赞!

                  

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com