Elasticsearch实现词云效果Demo

news/2024/7/7 6:40:21 标签: elasticsearch, 大数据, java, 全文检索

文章目录

  • 前言
  • 前期准备
    • springboot+Elasticsearch依赖
  • 思路
    • 准备数据
    • 查询数据
    • 处理文本
    • 样式处理
  • 具体实施
    • 数据准备
    • 创建索引
    • 数据存储
    • 进行查询
  • 踩坑记录
    • 聚合查询不生效问题
  • demo地址
  • 总结

前言

最近项目中使用Elasticsearch在做快速查询的功能,然后就想到了之前的一个项目中有一个词云的功能,就想用Elasticsearch实现一下词云的效果,实现思路很简单,目前这个demo已经写完了,透露一下很简陋,如何想要在项目中实际应用还需要改进。

前期准备

springboot+Elasticsearch依赖

版本我用的springboot 2.3.12.RELEASE对应的Elasticsearch是7.6.2

<!--        elasticsearch相关依赖-->
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
        </dependency>
        
        <!-- ikanalyzer 中文分词器  -->
        <dependency>
            <groupId>com.janeluo</groupId>
            <artifactId>ikanalyzer</artifactId>
            <version>2012_u6</version>
        </dependency>

在这里插入图片描述

思路

准备数据

将需要生成词云的文本数据存储到ES中。可以将文本拆分为单个词语,并将其作为文档的字段保存到ES中。

查询数据

使用ES的查询功能检索文档数据。可以根据业务需求编写查询语句,以获取需要的文本数据。

处理文本

将查询到的文本数据进行处理,例如去除停用词、统计词频等。

样式处理

这个不在本文章的范畴内,在上面的步骤就已经简单的实现一部分高频词的内容了,所以下面的这些是属于具体业务了,本文只提供一个思路和demo

  • 选择关键词:根据需求,可以根据词频进行排序,选择一定数量的高频词作为关键词。

  • 生成词云:使用词云生成工具库(如WordCloud)来生成词云图像。根据关键词的频率和重要性,在画布上布局词语,并设置相应的颜色、字体等样式。

  • 展示词云:将生成的词云图像展示在前端页面或保存为图片文件。如果在网页中展示,可以使用HTML和CSS来控制布局和样式。

具体实施

数据准备

就是单纯的准备数据阶段,使用下面这个数据中的数据随机生成一些句子,然后再使用Ik的工具包进行分词,分词以后存储到ES中

java">    static  final String[] CHINESE_WORDS = {
            "我", "你", "他", "她", "它",
            "是", "的", "在", "这", "那",
            "很", "真", "爱", "喜欢",
            "美丽", "快乐", "拥抱", "友情", "理解",
            "幸福", "梦想", "努力", "成功", "明天",
            "希望", "勇气", "坚定", "自信", "感恩",
            "热爱", "青春", "成长", "智慧", "创新",
            "开心", "失落", "放弃", "挑战", "困难",
            "奋斗", "拼搏", "汗水", "收获", "感动",
            "祝福", "寂寞", "无聊", "闲暇", "旅游",
            "信任", "包容", "尊重", "宽容", "耐心"
    };

   /**
     * @description: 使用IK对这些句子进行分词
     * @author: gepengjun
     * @date: 2023/9/8 10:09
     * @param: []
     * @return: java.util.List<java.lang.String>
     **/
    List<String> fenci() throws IOException {

            String text = "我喜欢使用IK分词器进行中文分词。";
        List<String> strings = generateRandomChineseSentences(20);
        String context="";
        for (String string : strings) {
            context+=string;
        }
        List<String> lists=new ArrayList<>();
        try (StringReader reader = new StringReader(context)) {
                IKSegmenter segmenter = new IKSegmenter(reader, true);
                Lexeme lexeme;
                while ((lexeme = segmenter.next()) != null) {
                    System.out.println(lexeme.getLexemeText());
                    lists.add(lexeme.getLexemeText());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        return lists;
    }

  /**
     * @description: 生成句子的
     * @author: gepengjun
     * @date: 2023/9/8 10:09
     * @param: [numSentences]生成多少条
     * @return: java.util.List<java.lang.String>
     **/
    private static List<String> generateRandomChineseSentences(int numSentences) {
        List<String> sentences = new ArrayList<>();

        Random random = new Random();

        for (int i = 0; i < numSentences; i++) {
            int numWords = random.nextInt(10) + 5; // 每个句子包含的词语数量范围为 5-14

            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < numWords; j++) {
                int index = random.nextInt(CHINESE_WORDS.length);
                sb.append(CHINESE_WORDS[index]);
            }

            String sentence = sb.toString();
            sentences.add(sentence);
        }

        return sentences;
    }

创建索引

存储数据前要先创建索引,在ES中索引你可以理解为数据库中的表

java">    @Test
    void createIndex(){
        // 创建ES连接
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("116.204.118.226", 9200, "http")));

        try {
            // 创建索引请求
            CreateIndexRequest request = new CreateIndexRequest("wordcloud");//简单理解就是建表

            // 设置索引的设置
            request.settings(Settings.builder()
                    .put("index.number_of_shards", 1)
                    .put("index.number_of_replicas", 1));

            // 设置索引的映射
            XContentBuilder mapping = XContentFactory.jsonBuilder()
                    .startObject()
                    .startObject("properties")
                    .startObject("context") //建表字段的过程
                    .field("type", "text")
                    .startObject("keyword") // 添加一个名为 "keyword" 的子字段
                    .field("type", "keyword") // 子字段类型为 keyword
                    .endObject()
                    .endObject()
                    .endObject()
                    .endObject();
            request.mapping("_doc",mapping);

            // 发送创建索引请求
            client.indices().create(request, RequestOptions.DEFAULT);

            System.out.println("索引创建成功!");

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭ES连接
            try {
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

注意这里,后面会用到
在这里插入图片描述

数据存储

注意我这些操作都是在单元测试中进行的

java">    @Test
    void insertData() throws IOException {
		// 创建一个 RestHighLevelClient 对象,用于与 Elasticsearch 进行通信
		RestHighLevelClient client = new RestHighLevelClient(
		        RestClient.builder(new HttpHost("localhost", 9200, "http")));
		
		// 创建一个 BulkRequest 对象,用于批量操作请求
		BulkRequest request = new BulkRequest();
		
		// 调用 fenci() 方法获取分词结果列表
		List<String> strings = fenci();
		
		// 遍历分词结果列表,将每个分词作为一个文档添加到 BulkRequest 中
		for (String word: strings) {
		    // 创建一个 IndexRequest 对象,并指定要添加到的索引名称和文档内容
		    request.add(new IndexRequest("wordcloud").source("context", word));
		}
		
		// 执行批量操作请求,并获取响应
		BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
        if (response.hasFailures()) {
            // 处理错误情况
            System.out.println("添加失败---------------------");
        } else {
            // 处理成功情况
            System.out.println("添加成功");
        }
    }

进行查询

这里使用了es的聚合查询,查询该索引下出现频率最高的前20个单词

java">    @Test
    void wrodCloud(){
        // 创建ES连接
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost", 9200, "http")));

        try {
            // 构建搜索请求
            SearchRequest request = new SearchRequest("wordcloud");
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            sourceBuilder.query(QueryBuilders.matchAllQuery());
            sourceBuilder.size(0); // 设置为0以仅返回聚合结果
            sourceBuilder.timeout(TimeValue.timeValueMinutes(1));

            // 添加词频统计的聚合
            sourceBuilder.aggregation(
                    AggregationBuilders.terms("word_count")
                            .field("context.keyword")
                            .size(20)); // 返回频率最高的 20 个词语

            request.source(sourceBuilder);

            // 执行搜索请求
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            ParsedStringTerms wordCount = response.getAggregations().get("word_count");
            for (Terms.Bucket bucket : wordCount.getBuckets()) {
                String word = bucket.getKeyAsString();
                long frequency = bucket.getDocCount();
                System.out.println("热门单词:"+word);
                System.out.println("出现次数:"+frequency);
                System.out.println("——————————————————————————————");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭ES连接
            try {
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

可以看到查询出来了20个单词,以及出现的频率,这样我们将这些单词以及频率进行一些简单的处理就能获得它们的占比,然后返回到前端展示,至于前端要使用什么用的控件或者框架是另一回事了,因为这些数据是准备好的。
在这里插入图片描述

踩坑记录

聚合查询不生效问题

这个问题就是上面创建索引中截图圈出来的部分,就是当我们对文本类型的数据进行聚合查询是需要设置它的子字段有一个keywrod类型的,然后在查询的时候指定这个(字段名.子字段名),这种方式就能正常的使用es的聚合查询了。
在 Elasticsearch 中,当需要对文本类型的字段进行聚合查询时,需要使用额外的 “keyword” 类型的子字段。这样做的目的是为了将文本数据转换为可进行聚合操作的结构。

设置 “keyword” 子字段的步骤如下:

  1. 创建索引时,在字段的映射中为文本字段添加一个子字段。
  2. 子字段的类型设置为 “keyword”,表示它是一个非分词的字符串类型。
  3. 可以为子字段指定任意的名称,不一定非得叫 “keyword”。

通过将字段的类型设置为 “keyword”,Elasticsearch 将保存原始文本数据,并允许对该子字段进行精确的分组统计操作,实现对文本字段的聚合查询。

demo地址

Demo地址

总结

关于使用这个es实现的这个效果,个人认为这只是一种方案,还有其它的,这里是直接使用的分词工具包,es上还可以安装分词插件,所以我的这种不一定是最好的,这是一种简单的方案希望大家不要被我的这种给迷惑了


http://www.niftyadmin.cn/n/5012103.html

相关文章

docker 部署vue

1&#xff1a; 首先部署nginx docker run --name nginx -d -p 88:80 nginx 2&#xff1a;访问 http://xxxxxxx:88/ 3: 进入nginx docker exec -it nginx /bin/sh 4: 回到vs&#xff0c;编译项目 npm run build 得到dist文件夹 5&#xff1a;创建docker 6&#xff1a; 将…

党建专题汇报片是什么

党建专题汇报片是以党的建设和发展为主题的一种专题性影片。它通过影像、文字、音频等多种表现手段&#xff0c;全面展示和宣传党的建设和发展情况&#xff0c;突出党的主张、方针、政策等内容&#xff0c;旨在加强党员教育培训、宣传党建成果、凝聚党员思想力量、推动党的事业…

微服务系统面经之三: 以秒杀系统为例-多级缓存及其更新机制

22 多级缓存&#xff08;百度一面&#xff09; 22.1 你用了什么缓存 答&#xff1a;本地内存redis 22.2 内存标记是如何被使用被更新的 22.3 什么时候修改这个第一层缓存&#xff08;内存标记&#xff09;&#xff0c;把它改为false 答&#xff1a;当redis预减库存为0的时…

Flink报错处理-1

在 flink job 运行一段时间后&#xff0c;观察日志发现出现了如下的 warn日志&#xff1a; The operator name {} exceeded the {} characters length limit and was truncated 完整的 warn 日志如下&#xff1a; The operator name TriggerWindow(GlobalWindows(), ListStat…

使用dockerfile文件部署Python+PyWebIO项目

1、安装docker 教程详见之前的内容。https://blog.csdn.net/weixin_44691253/category_12101661.html 2、打包好Python项目 之前的文章中有提到我编写测试工具使用的框架&#xff1a;PythonRequestsPyWebIO框架详解&#xff0c;编写测试工具提高团队测试效率 打包项目时&am…

软考高级系统架构设计师系列案例考点专题五:Web应用开发

软考高级系统架构设计师系列案例考点专题五:Web应用开发 一、Web应用技术分类二、数据库与Web服务器三、应用服务器集群四、负载均衡技术1.应用层负载均衡技术2.传输层负载均衡技术五、数据库读写分离化六、用缓存缓解库读取压力七、有状态和无状态八、内容分发网络九、表述性…

uniapp 悬浮窗-任意界面 Ba-FloatWinWeb

简介&#xff08;下载地址&#xff09; Ba-FloatWinWeb 是一款支持自定义任意界面的悬浮窗插件。采用webview方式&#xff0c;同时支持本地、网络地址&#xff1b;自带几种界面&#xff0c;可直接使用。 支持显示、更新、隐藏支持记录显示位置支持拖动支持监听点击事件支持自…

opencv基础: 视频,摄像头读取与保存的常用方法

当然还可以从视频中抓取截图&#xff0c;所以现在聊一下常用的抓取视频截图的的方法。 VideoCapture 方法 cv2.VideoCapture();cv2.VideoCapture( device);cv2.VideoCapture(filename);上面有三种构造方法&#xff0c; 第一种是无法构造方法。 第二种参数device是一个数字。 …