面试集中营—ElasticSearch架构篇

news2024/11/25 10:13:01

一、为什么用ElasticSearch?

       1、支持多种数据类型。它可以处理非结构化、数值和地理信息等多种类型的数据;

       2、简单的RESTful API。ES提供了一个简单易用的RESTful API,使得它可以从任何编程语言中调用,降低了学习的曲线。

       3、近实时搜索。ES每隔1秒将数据存储至系统缓存中,使用倒排索引提高检索效率,使得搜索数据变得快速且高效。

       4、支持相关性搜索。它可以根据条件对搜索结果进行打分,提供了基于文档的全文检索能力。

       5、天然分布式存储。ES是分布式的,使用分片支持处理PB级的数据量,易于扩展,可部署在数百台服务器的集群中。

      6、降低全文检索的学习曲线。它可以被任何编程语言调用,使得开发变得更加容易。

      7、高可用性。由于其分布式特性,ES可以通过添加更多节点来分担负载,增加可靠性,无需对应用进行任何改动。

二、ES基本概念名词

Cluster

       代表一个集群,集群中有多个节点,其中有一个为主节点,这个主节点是可以通过选举产生的,主从节点是对于集群内部来说的。ES的一个概念就是去中心化,字面上理解就是无中心节点,这是对于集群外部来说的,因为从外部来看es集群,在逻辑上是个整体,你与任何一个节点的通信和与整个es集群通信是等价的。

Shards

        代表索引分片,es可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上。构成分布式搜索。分片的数量只能在索引创建前指定,并且索引创建后不能更改

replicas

        代表索引副本,es可以设置多个索引的副本。

        副本的作用:

        一是提高系统的容错性,当某个节点某个分片损坏或丢失时可以从副本中恢复。

        二是提高es的查询效率,es会自动对搜索请求进行负载均衡。

Recovery

        代表数据恢复或叫数据重新分布,es在有节点加入或退出时会根据机器的负载对索引分片进行重新分配;挂掉的节点重新启动时也会进行数据恢复。

三、ES基础架构

     角色

       五大角色:

       Master Node

        主节点,该节点不和应用创建连接,每个节点都保存了集群状态,master节点控制整个集群的元数据。只有master节点可以修改节点状态信息及元数据的处理,比如索引的新增、删除、分片路由分配、所有索引和相关Mapping、Setting配置等等。

       Master eligible nodes

       合格主节点。合格节点,每个节点部署后不修改配置信息,默认就是一个 eligible 节点。有资格成为Master节点但暂时并不是Master的节点被称为 eligible 节点,该节点可以参加选主流程,成为Mastere节点。该节点只是与集群保持心跳,判断Master是否存活,如果Master故障则参加新一轮的Master选举。

       Data Node

        数据节点,用于简历文档索引,接受应用创建连接,接受索引请求,接受用户的搜索请求。是真实春初数据的节点,正常情况下节点数量越多,集群的性能就越强大

       Coordinating Node

        协调节点(/路由节点/client节点) 协调节点,该节点专用与接收应用的查询连接、接受搜索请求,但其本身不负责存储数据。

       协调节点接受客户端搜索请求后将请求转发到与查询条件相关的多个data节点的分片上,然后多个data节点的分片执行查询语句或者查询结果再返回给协调节点,协调节点把各个data节点的返回结果进行整合、排序等一系列操作后再将最终结果返回给用户请求。

        搜索请求在两个阶段中执行(query 和 fetch),这两个阶段由接收客户端请求的节点 - 协调节点协调。在请求query 阶段,协调节点将请求转发到保存数据的数据节点。 每个数据节点在本地执行请求并将其结果返回给协调节点。在收集fetch阶段,协调节点将每个数据节点的结果汇集为单个全局结果集。

       Ingest Node

        ingest 节点可以看作是数据前置处理转换的节点,支持 pipeline管道设置,可以使用 ingest 对数据进行过滤、转换等操作,类似于 logstash 中 filter 的作用,功能相当强大。

        Ingest节点处理时机:在数据被索引之前,通过预定义好的处理管道对数据进行预处理。默认情况下,所有节点都启用Ingest,因此任何节点都可以处理Ingest任务。

        ingest的详细可以参考elasticsearch高可用 原理 (图解+秒懂+史上最全)-CSDN博客

        存储结构

           Elasticsearch -> Index-> Types -> Documents -> Fields

           1、ES的index代表Mysql中的数据库

           2、ES的types代表Mysql中的Tables,新版本中弱化types概念

           3、ES的Document代表Mysql中的行

           4、ES的Fields代表Mysql中的列

           5、ES的mapping代表Mysql中的表结构,

         由于Elasticsearch底层使用了lucene的原因,不支持对mapping的修改,可使用索引重建的方式。而且不能更改类型,为什么不能修改一个字段的type?原因是一个字段的类型修改以后,那么该字段的所有数据都需要重新索引。Elasticsearch底层使用的是lucene库,字段类型修改以后索引和搜索要涉及分词方式等操作,不允许修改类型在我看来是符合lucene机制的。

          存储就是集群,分片,副本。如下图所示

      Lucene

        Lucene是使用Java语言开发的开源的,高性能的查询库。Apache Solr,Apache Nutch,OpenSearch和Elasticsearch都是在Lucene的基础上创建的。Lucene已经有超过20年的历史,是Apache基金会管理的成熟项目。

        Lucene的核心是倒排索引(inverted search index),这是Lucene有快速查询能力的核心。倒排索引提供了关键词与包含关键词的文档的对应关系。在查询的过程中,从排序的列表中快速找到关键词并且找到关键词对应的文档列表。Lucene支持的信息类型包含数字、字符串以及文本类型。Lucene包含丰富的搜索接口,支持自然语言搜索,通配符搜索,模糊搜索和邻近搜索。

      倒排索引

        所谓倒排索引,就是相对于正排索引,正排索引典型例子就是mysql的B+树主键索引,一个索引字段对应一列数据,key是主键ID,value是内容。而倒排索引,key是内容,value是关联的主键列表。如下图所示。

      倒排索引有什么优点呢?

       1、快速查找包含特定单词的文档,这使得它特别适合用于搜索引擎和文本搜索应用。

       2、倒排索引可以快速查找文档集合中包含多个单词的文档,这在文本分类和关键词提取中也很有用、

       缺点:

       1、额外的存储空间来存储索引;

       2、倒排索引在建立和更新时需要一定的时间;

     Lucene中的倒排索引

        lucene就是影响最为广泛的一款倒排索引及搜索工具,lucene把关键字按照字典顺序的存储在磁盘上,这样可以充分的发挥二分查找的优势,加快查找的速度。

      存储内容      

term indexterm dictionaryPosting List
小米1,2...4
华为1,4,6
手机1,2,3...6

        FST

       新增一条数据的过程

        1、分词

        lucene使用字典文件记录所有的关键字,每个关键字不会重复。这个关键字是通过分词来完成的,如果是英文很简单就是按照英文单词来分割,但是中文就需要一个中文的分词器。

        2、分析整理

        下一步就是对分割出来的词进行分析和整理,比如时态统一,去除不需要的词比如“是”,“的”等等

       3、建立对应关系

      最后就是把关键词和对应的文件id关联上,一个关键词可以关联多个文件id。

      对索引的压缩算法

       针对海量的数据,会产生大量的索引文件,如果不对索引进行压缩,可以想见光索引文件就需要大量的硬件资源,同时对于索引的检索也会更加费时。此时压缩算法就非常必要了。

       1、大量的对数字的压缩

       索引中的Posting List不管主键Id是什么数据类型的,统一都是int类型,最大能够表示的正整数是2的31次方减1,当id很大的时候,比如存储两个连续的大整数,比如[1000000000,1000000001]这两个数字压缩之后可能会成为[100000000,1]类似的情况,后面的1表示和前一个数字的差值。因为 Posting List的id不一定是连续的但是肯定是有序的。所以使用差值列表来存储[Posting List]。

      2、关键词压缩

      比如有很多关键词都有相同的文字,比如中国,中国人,中国话,都有中国,那么就会把中国作为一个编码,变成中国,<1,人>,<1,话>

四、Elasticsearch数据备份与恢复

快照和还原机制

        Snapshot: 快照,是Elasticsearch中用于备份数据的核心概念。Snapshot是一个时间点上的数据的完整拷贝,可以用于恢复数据或迁移到其他集群。
        Restore: 还原,是从Snapshot中恢复数据的过程。Restore可以用于恢复单个索引或整个集群。 

        创建快照:curl -X PUT "http://localhost:9200/_snapshot/my_snapshot/snapshot_1?wait_for_completion=true" -H 'Content-Type: application/json' -d' { "indices": "my_index", "ignore_unavailable": true, "include_global_state": false }' 
        恢复快照:curl -X POST "http://localhost:9200/_snapshot/my_snapshot/snapshot_1/_restore" -H 'Content-Type: application/json' -d' { "indices": "my_index", "ignore_unavailable": true }' 或者使用elasticsearch-snapshot工具恢复快照: bin/elasticsearch-snapshot restore my_snapshot snapshot_1

分页查询与插入

        可以使用scroll分页查询的方式,按照时间周期,从源ES中导入到目标ES中。代码如下:

// 设定滚动时间间隔
        final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1L));
        SearchRequest searchRequest = new SearchRequest(formIndices);
        searchRequest.scroll(scroll);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 设定每次返回多少条数据
        int number = size + new Random().nextInt(size / 2);
        searchSourceBuilder.size(number);
        searchRequest.source(searchSourceBuilder);

        SearchResponse searchResponse;
        try {
            CountRequest countRequest = new CountRequest(formIndices);
            CountResponse countResponse = client.count(countRequest, getNewOptions());
            total = countResponse.getCount();
            searchResponse = client.search(searchRequest, getNewOptions());
        } catch (IOException e) {
            LOGGER.error("formIndices:" + formIndices, e);
            return;
        }
        count = count + searchResponse.getHits().getHits().length;
        String scrollId = searchResponse.getScrollId();
        SearchHit[] searchHits = searchResponse.getHits().getHits();
        LOGGER.info("-----首页-----" + System.currentTimeMillis());
        request = new BulkRequest();
        for (SearchHit documentFields : searchHits) {
            Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();
            String timestamp = (String) sourceAsMap.get("@timestamp");
            // 过滤path
            String path = (String) sourceAsMap.get("path");
            if(checkDiscardPath(path)){
                continue;
            }
            if (!StringUtils.isEmpty(timestamp)) {
                try {
                    sourceAsMap.put("@timestamp", toIndices + timestamp.substring(10));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            Map<String, Object> httpMap = (Map<String, Object>) sourceAsMap.get("http");
            if (httpMap != null && httpMap.size() > 0) {
                Map<String, Object> requestMap = (Map<String, Object>) httpMap.get("request");
                if (requestMap != null && requestMap.size() > 0) {
                    requestMap.remove("body");
                    requestMap.remove("params");
                    httpMap.put("request", requestMap);
                }
                Map<String, Object> responseMap = (Map<String, Object>) httpMap.get("response");
                if (responseMap != null && responseMap.size() > 0) {
                    responseMap.remove("body");
                    httpMap.put("response", responseMap);
                }
                sourceAsMap.put("http", httpMap);
            }
            indexRequest = new IndexRequest("ai-cloud-gateway-prod-packet-" + toIndices)
                    .source(sourceAsMap);
            request.add(indexRequest);
        }
        // 写
        BulkResponse bulk = clientNew.bulk(request, getNewOptions());
        LOGGER.info(bulk.status().getStatus() + ":" + System.currentTimeMillis());
        SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
        // 遍历搜索命中的数据,直到没有数据
        while (searchHits.length > 0) {
            try {
                scrollRequest.scroll(scroll);
                try {
                    searchResponse = client.scroll(scrollRequest, getNewOptions());
                } catch (IOException e) {
                    e.printStackTrace();
                    errorTimes++;
                    continue;
                }
                scrollId = searchResponse.getScrollId();
                searchHits = searchResponse.getHits().getHits();
                if (searchHits.length == 0) {
                    LOGGER.info(" searchHits is null -----  end");
                    break;
                } else {
                    LOGGER.info(" searchHits is  not null ----- " + searchHits.length);
                }
                count = count + searchHits.length;
                LOGGER.info("-----下一页-----");
                request = new BulkRequest();

                LOGGER.info("-----过滤前----- {}",searchHits.length);
                SearchHit[] finalSearchHits = checkDiscardHits(searchHits);
                LOGGER.info("-----过滤后----- {}",finalSearchHits.length);
                IndexRequest[] requests = new IndexRequest[finalSearchHits.length];
                CountDownLatch countDownLatch = new CountDownLatch(finalSearchHits.length);
                try {
                    for (int i = 0; i < finalSearchHits.length; i++) {
                        int finalI = i;
                        // 清除 request  response 中的body 减少数据量
                        executorServiceTwo.execute(() -> {
                            try {
                                Map<String, Object> sourceAsMap = finalSearchHits[finalI].getSourceAsMap();
                                String timestamp = (String) sourceAsMap.get("@timestamp");
                                sourceAsMap.put("@timestamp", toIndices + timestamp.substring(10));
                                Map<String, Object> httpMap = (Map<String, Object>) sourceAsMap.get("http");
                                if (httpMap != null && httpMap.size() > 0) {
                                    Map<String, Object> requestMap = (Map<String, Object>) httpMap.get("request");
                                    if (requestMap != null && requestMap.size() > 0) {
                                        requestMap.remove("body");
                                        requestMap.remove("params");
                                        httpMap.put("request", requestMap);
                                    }
                                    Map<String, Object> responseMap = (Map<String, Object>) httpMap.get("response");
                                    if (responseMap != null && responseMap.size() > 0) {
                                        responseMap.remove("body");
                                        httpMap.put("response", responseMap);
                                    }
                                    sourceAsMap.put("http", httpMap);
                                }
                                requests[finalI] = new IndexRequest("ai-cloud-gateway-prod-packet-" + toIndices)
                                        .source(sourceAsMap);
                                countDownLatch.countDown();
                            } catch (Exception e) {
                                LOGGER.error("", e);
                            }
                        });
                    }
                } catch (Exception e) {
                    LOGGER.error("", e);
                    Map<String, Object> sourceAsMap;
                    for (SearchHit documentFields : searchHits) {
                        sourceAsMap = documentFields.getSourceAsMap();
                        // 过滤path
                        String path = (String) sourceAsMap.get("path");
                        if(checkDiscardPath(path)){
                            continue;
                        }
                        String timestamp = (String) sourceAsMap.get("@timestamp");
                        if (!StringUtils.isEmpty(timestamp)) {
                            try {
                                sourceAsMap.put("@timestamp", toIndices + timestamp.substring(10));
                            } catch (Exception ee) {
                                LOGGER.error("", ee);
                            }
                        }
                        Map<String, Object> httpMap = (Map<String, Object>) sourceAsMap.get("http");
                        if (httpMap != null && httpMap.size() > 0) {
                            Map<String, Object> requestMap = (Map<String, Object>) httpMap.get("request");
                            if (requestMap != null && requestMap.size() > 0) {
                                requestMap.remove("body");
                                requestMap.remove("params");
                                httpMap.put("request", requestMap);
                            }
                            Map<String, Object> responseMap = (Map<String, Object>) httpMap.get("response");
                            if (responseMap != null && responseMap.size() > 0) {
                                responseMap.remove("body");
                                httpMap.put("response", responseMap);
                            }
                            sourceAsMap.put("http", httpMap);
                        }
                        indexRequest = new IndexRequest("ai-cloud-gateway-prod-packet-" + toIndices)
                                .source(sourceAsMap);
                        request.add(indexRequest);
                        countDownLatch.countDown();
                    }
                }

                try {
                    countDownLatch.await(60, TimeUnit.SECONDS);
                } catch (InterruptedException e) {
                    LOGGER.warn("InterruptedException", e);
                }
                LOGGER.info("request {}",requests.length);
                request.add(requests);
                // 写
                LOGGER.info("begin writing to " + toIndices + ",from" + formIndices);
                bulk = clientNew.bulk(request, getNewOptions());
                LOGGER.info(bulk.status().getStatus() + ":" + System.currentTimeMillis());

                if (count >= total - 5000) {
                    break;
                }
                Thread.sleep(100);
            } catch (Exception e) {
                ......
            }
        }

  完整代码:GitHub - EricLoveMia/elasticsearch-import

五、性能调优

1、不要返回数据量非常大的结果集

2、避免出现大文档,即单条索引记录的体积不要过大。

3、有条件的话尽量使用大的内存,SSD硬盘,分配给ES的内存为最大内存的50%;

4、尽量批请求bulk;

5、大量写入的情况下,增加索引刷新时间大小index.refresh_interval,默认1s刷新一次,设置为-1表示关闭索引刷新;

6、初始加载数据时禁用副本,将index.number_of_replicas 设置为0;

7、尽量避免使用深度分页,实在不能避免可以采用Scroll 遍历查询或Search After 查询;

8、Data too large 的报错。下图可以看到有两条界限:驱逐线 和 断路器。当缓存数据到达驱逐线时,会自动驱逐掉部分数据,把缓存保持在安全的范围内。当用户准备执行某个查询操作时,断路器就起作用了,缓存数据+当前查询需要缓存的数据量到达断路器限制时,会返回Data too large错误,阻止用户进行这个查询操作。

        此时就要根据情况来修改一些参数的值。

        indices.fielddata.cache.size :配置fieldData的Cache大小,可以配百分比也可以配一个准确的数值。cache到达约定的内存大小时会自动清理,驱逐一部分FieldData数据以便容纳新数据。默认值为unbounded无限。
        indices.fielddata.cache.expire:用于约定多久没有访问到的数据会被驱逐,默认值为-1,即无限。expire配置不推荐使用,按时间驱逐数据会大量消耗性能。而且这个设置在不久之后的版本中将会废弃。

        indices.breaker.fielddata.limit:这个 fielddata 断路器限制fielddata的大小,默认情况下为堆大小的60%。
        indices.breaker.request.limit:这个 request 断路器估算完成查询的其他部分要求的结构的大小, 默认情况下限制它们到堆大小的40%。
        indices.breaker.total.limit:这个 total 断路器封装了 request 和 fielddata 断路器去确保默认情况下这2个部分使用的总内存不超过堆大小的70%。

参考:

elasticsearch高可用 原理 (图解+秒懂+史上最全)-CSDN博客

elasticsearch常识:存储结构、优化_es的存储结构-CSDN博客

Elasticsearch数据备份与恢复-CSDN博客

ES性能调优详解-CSDN博客

ElasticSearch:从[FIELDDATA]Data too large错误看FieldData配置_indices.fielddata.cache.size-CSDN博客ES 性能调优,这可能是全网最详细的 Elasticsearch 性能调优指南_es性能优化-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1632584.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HUST华科校园网自动登录

HUST校园网开机自动登录&#xff0c;后台保活 校园网虽然有无感认证&#xff0c;但是每次还得弹出网页&#xff0c;再点击一次连接&#xff0c;还是挺麻烦的。而且对于一部分开机自启的联网app来说&#xff0c;每次开机后无网络可能导致某些应用功能出bug或者其他异常行为。因此…

笃行致远,“易”往无前 | 易保全成立10周年啦

日月其迈&#xff0c;岁律更新。2024年4月28日&#xff0c;易保全迎来了10周岁生日。10年磨一剑&#xff0c;易保全创立至今&#xff0c;始终坚定自己的初心和使命&#xff0c;在时代的激流勇进中&#xff0c;以电子数据保全机构的身份与中国区块链共成长。 “创”说十年&…

Blender常见操作

1.局部视图&#xff1a;Local View&#xff0c;也可称作Solo模式&#xff0c;按快捷键 “/”进入&#xff0c;在按退出&#xff0c;只显示选中的物体&#xff08;可多选&#xff09;&#xff0c;方便编辑 2.物体合并&#xff1a;Ctrl J 其中&#xff0c;当选中多个物体时&am…

CSS border边框(理解网页边框制作)

目录 一、border边框介绍 1.概念 2.特点 3.功能 4.应用 二、border边框用法 1.border边框属性 2.边框样式 3.边框宽度 4.边框颜色 5.边框-单独设置各边 6.边框-简写属性 三、border边框属性 四、border边框实例 1.创建带有阴影效果的边框&#xff1a; 2. 创建一个类似标…

如何使用SOCKS5代理?

SOCKS5 是一个代理协议&#xff0c;在使用TCP/IP协议通讯的前端机器和服务器机器之间扮演一个中介角色&#xff0c;使得内部网中的前端机器变得能够访问Internet网中的服务器&#xff0c;或者使通讯更加安全。那么&#xff0c;SOCKS5代理该如何使用呢&#xff1f; 首先需要获取…

Aiseesoft Blu-ray Player for Mac:蓝光播放器

Aiseesoft Blu-ray Player for Mac是一款功能强大且易于使用的蓝光播放器&#xff0c;专为Mac用户打造。它以其卓越的性能和简洁的操作界面&#xff0c;为用户带来了全新的高清蓝光播放体验。 Aiseesoft Blu-ray Player for Mac v6.6.50激活版下载 这款软件支持播放任何高质量的…

2024年4月中国数据库排行榜:OceanBase再度登顶,KingBase稳步上升进前五

春风劲吹&#xff0c;迎来了2024年4月中国流行度排行榜。纵观本月榜单&#xff0c;各家数据库产品你追我赶&#xff0c;名次呈现微妙变动&#xff0c;它们正以不可忽视的力量&#xff0c;推动着中国乃至全球的数据管理革新。在这春意盎然的四月&#xff0c;让我们继续关注这些数…

命令执行。

命令执行 在该项目的readme中&#xff0c;描述了怎么去调用的flink 通过java原生的runtime来调用flink&#xff0c;下一步就是去看看具体的调用过程了&#xff0c;是否存在可控的参数 找到具体提交命令的类方法CommandRpcClinetAdapterImpl#submitJob() 这里要确定command&am…

【ESP32S3】使用 Flash 下载工具完成 Flash 加密功能

此篇文档记录通过 Flash 下载工具 完成 Flash 加密 功能的实现&#xff0c;此文档不启用 Flash 加密方案的 NVS 加密。 Flash 加密启动的验证代码&#xff1a;esp-idf/components/bootloader_support/src/flash_encrypt.c Flash 加密测试例程&#xff1a;esp-idf/examples/sec…

Qt绘图与图形视图之自定义图元实现拖拽、拉伸、旋转功能

往期回顾 Qt绘图与图形视图之移动鼠标手动绘制任意多边形的简单介绍-CSDN博客 Qt绘图与图形视图之场景、视图架构的简单介绍-CSDN博客 Qt绘图与图形视图之基本图元绘制的简单介绍-CSDN博客 Qt绘图与图形视图之自定义图元实现拖拽、拉伸、旋转功能 一、最终效果 实现对自定义图…

Agent AI智能体在未来,一定与你我密不可分

随着Agent AI智能体的逐渐成熟&#xff0c;人工智能应用的不断深入与拓展&#xff0c;相信在不久的将来&#xff0c;他与你我的生活一定是密不可分的。 目录 ​编辑 1 Agent AI智能体是什么&#xff1f; 2 Agent AI在语言处理方面的能力 2.1 情感分析示例 2.2 文本分类任…

Tetra Pak利乐中试工厂仿真 - 工艺开发、配方开发和无菌灌装的试验

此模型是基于速率的模型&#xff0c;使用Rate模块库中的离散速率模块和Item模块库中的离散事件模块。速率模块库位于ExtendSim Pro中。 利乐中试工厂&#xff08;得克萨斯州丹顿&#xff09;进行工艺开发、配方开发和无菌灌装的试验。它还对新的加工和灌装设备进行内部测试。该…

Colab用例与Gemma快速上手指南:如何在Colab和Kaggle上有效地运用Gemma模型进行机器学习任务

&#x1f42f; Colab用例与Gemma快速上手指南 &#x1f680; 文章目录 &#x1f42f; Colab用例与Gemma快速上手指南 &#x1f680;摘要引言正文&#x1f4dd; **基础使用&#xff1a;Gemma快速上手**环境设置和模型加载安装必要的库加载Gemma模型 推理示例 &#x1f6e0; **Ge…

秋招后端开发面试题 - Java语言基础(上)

目录 Java基础上前言面试题Java 语言的特点JVM JDK JRE什么是跨平台性&#xff1f;原理是什么&#xff1f;什么是字节码?采用字节码的好处是什么?Java 和 C 的区别&#xff1f;注释&#xff1f;关键字关键字 instanceof类型转换关键字 this 和 super关键字 final finally fin…

【CGALDotNet】CGAL的C#封装(C#调用编译好的CGAL的dll)

介绍 开源项目出处&#xff08;两个模块&#xff09;&#xff1a; 链接1&#xff1a;https://github.com/Scrawk/CGALDotNet/tree/master?tabreadme-ov-file 链接2&#xff1a;https://github.com/Scrawk/CGALDotNetGeometry 该项目提供了编译的、封装相关接口后的CGAL库&am…

纯js对比excel小工具

如何使用JavaScript和xlsx.js实现Excel文件对比&#xff1a;实战指南 在日常办公或数据分析工作中&#xff0c;我们经常需要比较两个Excel文件中的数据差异。手动对比不仅耗时费力&#xff0c;还容易出错。本文将带你通过一个简单的网页应用&#xff0c;利用JavaScript和开源库…

Spring AI聊天功能开发

一、引入依赖 继承父版本的springboot依赖&#xff0c;最好是比较新的依赖。 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.4</version><relativePat…

transformer上手(10)—— 文本摘要任务

文本摘要是一个 Seq2Seq 任务&#xff0c;尽可能保留文本语义的情况下将长文本压缩为短文本。 文本摘要可以看作是将长文本“翻译”为捕获关键信息的短文本&#xff0c;因此大部分文本摘要模型同样采用 Encoder-Decoder 框架。当然&#xff0c;也有一些非 Encoder-Decoder 框架…

低代码技术在构建质量管理系统中的应用与优势

引言 在当今快节奏的商业环境中&#xff0c;高效的质量管理系统对于组织的成功至关重要。质量管理系统帮助组织确保产品或服务符合客户的期望、符合法规标准&#xff0c;并持续改进以满足不断变化的需求。与此同时&#xff0c;随着技术的不断进步&#xff0c;低代码技术作为一…

Linux系统编程---线程池并发服务器

模型原理分析&#xff1a; 线程池的关键优势在于它减少了每次任务执行时创建和销毁线程的开销 线程池的组成主要分为 3 个部分&#xff0c;这三部分配合工作就可以得到一个完整的线程池&#xff1a; 1. 任务队列&#xff0c;存储需要处理的任务&#xff0c;由工作的线程来处理…