当前位置: 首页 > article >正文

使用Apache Lucene构建高效的全文搜索服务

使用Apache Lucene构建高效的全文搜索服务

在现代应用程序中,全文搜索功能是不可或缺的一部分。无论是电子商务网站、内容管理系统,还是数据分析平台,快速、准确地搜索大量数据是提升用户体验的关键。Apache Lucene 是一个强大的全文搜索引擎库,它提供了高效的索引和搜索功能,能够轻松集成到Java应用程序中。本文将介绍如何使用Apache Lucene构建一个高效的全文搜索服务,并通过一个实际的Java代码示例来展示其核心功能。

1. Lucene简介

Apache Lucene 是一个高性能、全功能的文本搜索引擎库,使用Java编写。它提供了强大的索引和搜索功能,支持多种查询类型,如布尔查询、范围查询、模糊查询等。Lucene的核心优势在于其高效的索引结构和灵活的API,使得开发者可以轻松地构建复杂的搜索功能。

2. 项目结构

在这个示例中,我们将构建一个简单的搜索服务,用于索引和搜索拍卖交易历史记录(AtcoinDealhistory)。项目的主要类 LuceneService 负责管理索引的创建、更新和搜索操作。

3. 索引创建与更新

在Lucene中,索引的创建和更新是通过 IndexWriter 来完成的。IndexWriter 负责将文档(Document)添加到索引中,并确保索引的高效存储和检索。

public void indexDocument(List<AtcoinDealhistory> list) throws IOException {long startTime = System.currentTimeMillis(); // 记录开始时间// 配置IndexWriterIndexWriterConfig config = new IndexWriterConfig(analyzer);config.setMaxBufferedDocs(20); // 设置最大缓冲文档数config.setRAMBufferSizeMB(2048.0); // 设置RAM缓冲区大小config.setUseCompoundFile(true); // 使用复合文件格式// 使用try-with-resources确保IndexWriter正确关闭try (IndexWriter indexWriter = new IndexWriter(directory, config)) {for (AtcoinDealhistory atcoinDealhistory : list) {Document doc = new Document();if (atcoinDealhistory.getAuctionId() != null) {// 添加字段到文档doc.add(new StringField("id", atcoinDealhistory.getId().toString(), Store.YES));doc.add(new StringField("auction_id", atcoinDealhistory.getAuctionId(), Store.YES));doc.add(new TextField("auction_name", atcoinDealhistory.getAuctionName(), Store.YES));doc.add(new StringField("amount", atcoinDealhistory.getAmount(), Store.YES));doc.add(new TextField("data", atcoinDealhistory.getData(), Store.YES));doc.add(new StringField("picture", atcoinDealhistory.getPicture(), Store.YES));// 处理日期字段if (atcoinDealhistory.getDealdate() != null) {try {SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");String dateStr = dateFormat.format(atcoinDealhistory.getDealdate());// 添加日期字段,用于排序doc.add(new SortedNumericDocValuesField("date", atcoinDealhistory.getDealdate().getTime()));// 添加日期字段,用于存储doc.add(new StringField("dealdate", dateStr, Store.YES));} catch (Exception e) {e.printStackTrace();}}}// 将文档添加到索引indexWriter.addDocument(doc);indexWriter.commit(); // 提交更改}} catch (Exception e) {e.printStackTrace();}long endTime = System.currentTimeMillis(); // 记录结束时间System.out.println("Index creation time: " + (endTime - startTime) + " milliseconds");
}

在这个方法中,我们首先配置了 IndexWriter,然后遍历 AtcoinDealhistory 对象列表,将每个对象的字段添加到 Document 中,并将其写入索引。我们还处理了日期字段,确保它们可以用于排序和存储。

4. 搜索功能

Lucene 的搜索功能是通过 IndexSearcher 来实现的。IndexSearcher 负责执行查询并返回匹配的文档。我们可以使用多种查询类型来构建复杂的搜索条件。

public List<AtcoinDealhistory> search(AtcoinDealhistory atcoinDealhistory) throws IOException, org.apache.lucene.queryparser.classic.ParseException {List<AtcoinDealhistory> results = new ArrayList<>();long startTime = System.currentTimeMillis(); // 记录开始时间// 打开索引目录try (DirectoryReader reader = DirectoryReader.open(directory)) {IndexSearcher searcher = new IndexSearcher(reader);BooleanQuery.Builder booleanQueryBuilder = new BooleanQuery.Builder();// 处理日期范围查询String startQueryDealDate = atcoinDealhistory.getStartQueryDealDate();String endQueryDealDate = atcoinDealhistory.getEndQueryDealDate();if (startQueryDealDate != null && endQueryDealDate != null) {TermRangeQuery dateRangeQuery = TermRangeQuery.newStringRange("dealdate", startQueryDealDate, endQueryDealDate, true, true);booleanQueryBuilder.add(dateRangeQuery, Occur.MUST);}// 处理金额范围查询Integer startQueryAmount = atcoinDealhistory.getStartQueryAmount();Integer endQueryAmount = atcoinDealhistory.getEndQueryAmount();if (startQueryAmount != null && endQueryAmount != null) {TermRangeQuery amountRangeQuery = TermRangeQuery.newStringRange("amount", Integer.toString(startQueryAmount), Integer.toString(endQueryAmount), true, true);booleanQueryBuilder.add(amountRangeQuery, Occur.MUST);}// 处理拍卖名称的关键词查询List<String> terms = analyzeQueryString(analyzer, atcoinDealhistory.getAuctionName());for (String term : terms) {TermQuery termQuery = new TermQuery(new Term("auction_name", term));booleanQueryBuilder.add(termQuery, Occur.MUST);}// 设置排序规则,根据日期字段降序排列SortField sortDate = new SortField("date", SortField.Type.LONG, true);Sort sort = new Sort(SortField.FIELD_SCORE, sortDate);// 执行查询ScoreDoc[] hits = searcher.search(booleanQueryBuilder.build(), 100, sort).scoreDocs;SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");// 遍历查询结果for (ScoreDoc hit : hits) {Document doc = searcher.doc(hit.doc);AtcoinDealhistory result = new AtcoinDealhistory();result.setId(Long.valueOf(doc.get("id")));result.setAuctionId(doc.get("auction_id"));result.setAuctionName(doc.get("auction_name"));result.setAmount(doc.get("amount"));result.setData(doc.get("data"));result.setPicture(doc.get("picture"));// 处理日期字段if (doc.get("dealdate") != null) {try {Date dealdate = dateFormat.parse(doc.get("dealdate"));result.setDealdate(dealdate);} catch (Exception e) {e.printStackTrace();}}results.add(result);}}long endTime = System.currentTimeMillis(); // 记录结束时间System.out.println("Index search time: " + (endTime - startTime) + " milliseconds");return results;
}

在这个方法中,我们首先打开索引目录并创建 IndexSearcher。然后,我们构建了一个布尔查询(BooleanQuery),用于处理日期范围、金额范围和关键词查询。最后,我们执行查询并遍历结果,将匹配的文档转换为 AtcoinDealhistory 对象并返回。

5. 分词器

Lucene 的分词器(Analyzer)用于将文本分解为单词或词语。在这个示例中,我们使用了 StandardAnalyzer,它是Lucene提供的一个标准分词器,适用于大多数英文文本。

	public LuceneService() throws IOException {// 索引目录的路径this.directory = FSDirectory.open(Paths.get(INDEX_DIR));// 标准索引解析器this.analyzer = new StandardAnalyzer();// 第三方分词器解析器
//		this.analyzer = new ReIKAnalyzer(false);}
public List<String> analyzeQueryString(Analyzer analyzer, String queryString) throws IOException {List<String> terms = new ArrayList<>();// 使用分词器处理查询字符串try (TokenStream tokenStream = analyzer.tokenStream("auction_name", new StringReader(queryString))) {CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);tokenStream.reset();// 遍历分词结果while (tokenStream.incrementToken()) {terms.add(charTermAttribute.toString());}tokenStream.end();}return terms;
}

这个方法将查询字符串分解为多个词语,并将它们添加到列表中,以便在搜索时使用。

6. 总结

通过这个示例,我们展示了如何使用Apache Lucene构建一个高效的全文搜索服务。Lucene提供了强大的索引和搜索功能,使得开发者可以轻松地处理复杂的搜索需求。无论是处理结构化数据还是非结构化文本,Lucene都能提供高效的解决方案。

7. 附录

maven 依赖

<!-- 搜索模块 --><!-- Lucene Core Dependency --><dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-core</artifactId><version>8.11.0</version> <!-- 请根据需要选择合适的版本 --></dependency><!-- Lucene Analyzers Dependency --><dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-analyzers-common</artifactId><version>8.11.0</version></dependency><!-- 如果需要其他Lucene模块,也可以继续添加 --><dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-queryparser</artifactId><version>8.11.0</version></dependency><dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-highlighter</artifactId><version>8.11.0</version></dependency><dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-memory</artifactId><version>8.11.0</version></dependency><dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-queries</artifactId><version>8.11.0</version></dependency><!-- <dependency><groupId>org.truenewx</groupId><artifactId>ik-analyzer-lucene</artifactId><version>5.0.1</version></dependency>--><dependency><groupId>com.github.keran213539</groupId><artifactId>IK_Analyzer</artifactId><version>2012FF_hf1_1</version></dependency><!-- https://mvnrepository.com/artifact/org.ansj/ansj_seg --><!-- <dependency><groupId>org.ansj</groupId><artifactId>ansj_seg</artifactId><version>5.1.6</version></dependency>-->

多线程索引创建

索引创建的时间有点久了,增加多线程处理

// 创建或更新索引public void indexDocument(List<AtcoinDealhistory> list) throws IOException {long startTime = System.currentTimeMillis(); // 记录开始时间//引入多线程ExecutorService executorService = Executors.newFixedThreadPool(numThreads);try {for (AtcoinDealhistory atcoinDealhistory : list) {executorService.submit(() -> {try {indexDocument(this.directory,this.analyzer,atcoinDealhistory);} catch (IOException e) {e.printStackTrace();}});}executorService.shutdown();executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);long endTime = System.currentTimeMillis(); // 记录结束时间// 计算索引创建时间long indexCreationTime = endTime - startTime;System.out.println("Index creation time: " + indexCreationTime/1000 + " milliseconds");} catch (Exception e) {System.out.println(e.getMessage());e.printStackTrace();} }

IK分词器重写

因为Lucene版本问题,IKAnalyzer 需要进行重写

package com.atcoin.busi.test;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.Tokenizer;
import org.wltea.analyzer.cfg.Configuration;public class ReIKAnalyzer extends Analyzer {private boolean useSmart;//分词器配置项private Configuration cfg;public Configuration getCfg() {return cfg;}public void setCfg(Configuration cfg) {this.cfg = cfg;}public boolean useSmart() {return useSmart;}public void setUseSmart(boolean useSmart) {this.useSmart = useSmart;}/*** IK分词器Lucene 5.4.0 Analyzer接口实现类** 默认细粒度切分算法*/public ReIKAnalyzer() {this(false);}/*** IK分词器Lucene 5.4.0 Analyzer接口实现类** @param useSmart*            当为true时,分词器进行智能切分*/public ReIKAnalyzer(boolean useSmart) {super();this.useSmart = useSmart;}/*** IK分词器Lucene 5.4.0 Analyzer接口实现类** @param cfg*/public ReIKAnalyzer(Configuration cfg) {super();this.setCfg(cfg);}/*** 重载Analyzer接口,构造分词组件** @param fieldName*            the name of the fields content passed to the*            TokenStreamComponents sink as a reader*/@Overrideprotected TokenStreamComponents createComponents(String fieldName) {Tokenizer _IKTokenizer = new ReIKTokenizer(this.useSmart());return new TokenStreamComponents(_IKTokenizer);}}
package com.atcoin.busi.test;
import java.io.IOException;import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
import org.wltea.analyzer.cfg.Configuration;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;public class ReIKTokenizer extends Tokenizer {// IK分词器实现private IKSegmenter _IKImplement;// 词元文本属性private final CharTermAttribute termAtt;// 词元位移属性private final OffsetAttribute offsetAtt;// 词元分类属性(该属性分类参考org.wltea.analyzer.core.Lexeme中的分类常量)private final TypeAttribute typeAtt;// 记录最后一个词元的结束位置private int endPosition;/*** Lucene 5.4.0 Tokenizer适配器类构造函数** @param in* @param useSmart*/public ReIKTokenizer(boolean useSmart) {super();offsetAtt = addAttribute(OffsetAttribute.class);termAtt = addAttribute(CharTermAttribute.class);typeAtt = addAttribute(TypeAttribute.class);_IKImplement = new IKSegmenter(input, useSmart);}/*** Lucene 5.4.0 Tokenizer适配器类构造函数** @param in* @param cfg*/public ReIKTokenizer(Configuration cfg) {super();offsetAtt = addAttribute(OffsetAttribute.class);termAtt = addAttribute(CharTermAttribute.class);typeAtt = addAttribute(TypeAttribute.class);_IKImplement = new IKSegmenter(input, cfg);}@Overridepublic boolean incrementToken() throws IOException {// 清除所有的词元属性clearAttributes();Lexeme nextLexeme = _IKImplement.next();if (nextLexeme != null) {// 将Lexeme转成Attributes// 设置词元文本termAtt.append(nextLexeme.getLexemeText());// 设置词元长度termAtt.setLength(nextLexeme.getLength());// 设置词元位移offsetAtt.setOffset(nextLexeme.getBeginPosition(),nextLexeme.getEndPosition());// 记录分词的最后位置endPosition = nextLexeme.getEndPosition();// 记录词元分类typeAtt.setType(nextLexeme.getLexemeTypeString());// 返会true告知还有下个词元return true;}// 返会false告知词元输出完毕return false;}@Overridepublic void reset() throws IOException {super.reset();_IKImplement.reset(input);}@Overridepublic final void end() {// set final offsetint finalOffset = correctOffset(this.endPosition);offsetAtt.setOffset(finalOffset, finalOffset);}
}

接口调用

package com.atcoin.busi.controller;
import java.io.IOException;
import java.util.List;import javax.annotation.PreDestroy;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import com.atcoin.busi.domain.AtcoinDealhistory;
import com.atcoin.busi.service.IAtcoinDealhistoryService;
import com.atcoin.busi.service.impl.LuceneService;@RestController
@RequestMapping("/lucene")
public class AtcoinLuceneController {@Autowiredprivate IAtcoinDealhistoryService atcoinDealhistoryService;@Autowiredprivate LuceneService luceneService;//    @PostMapping("/index")
//    public String indexDocument(@RequestParam String id, @RequestParam String content) {
//        try {
//            luceneService.indexDocument(id, content);
//            return "Document indexed successfully.";
//        } catch (IOException e) {
//            e.printStackTrace();
//            return "Failed to index document.";
//        }
//    }@GetMapping("/createIndex")public String createIndex() {try {List<AtcoinDealhistory> list = atcoinDealhistoryService.selectAtcoinDealhistoryIndex();luceneService.indexDocument(list);return "Document indexed successfully.";} catch (IOException e) {e.printStackTrace();return "Failed to index document.";}}@GetMapping("/search")public List<AtcoinDealhistory> search(@RequestParam String keywords) {try {return luceneService.search(keywords);} catch (IOException | org.apache.lucene.queryparser.classic.ParseException e) {e.printStackTrace();return null;}}// 在应用关闭时关闭Lucene资源@PreDestroypublic void close() {try {luceneService.close();} catch (IOException e) {e.printStackTrace();}}
}

相关文章:

使用Apache Lucene构建高效的全文搜索服务

使用Apache Lucene构建高效的全文搜索服务 在现代应用程序中&#xff0c;全文搜索功能是不可或缺的一部分。无论是电子商务网站、内容管理系统&#xff0c;还是数据分析平台&#xff0c;快速、准确地搜索大量数据是提升用户体验的关键。Apache Lucene 是一个强大的全文搜索引擎…...

VScode在Windows11中配置MSVC

因为MSVC编译器在vs当中&#xff0c;所以我们首先要安装vs的一部分组件。如果只是需要MSVC的话&#xff0c;工作负荷一个都不需要勾选&#xff0c;在单个组件里面搜索MSVC和windows11 SDK&#xff0c;其中一个是编译器&#xff0c;一个是头文件然后右下角安装即可。搜索Develop…...

【洛谷贪心算法题】P2240部分背包问题

【解题思路】 贪心策略选择 对于部分背包问题&#xff0c;关键在于如何选择物品放入背包以达到最大价值。由于物品可以分割&#xff0c;遍历排序后的物品数组&#xff0c;根据物品重量和背包剩余容量的关系&#xff0c;决定是将整个物品放入背包还是分割物品放入背包&#xff…...

DevOps原理和实现面试题及参考答案

解释 DevOps 的核心目标与文化价值观,如何理解 “CAMS” 模型? DevOps 的核心目标是打破开发(Development)和运维(Operations)之间的壁垒,通过自动化、协作和持续反馈,实现软件的快速、可靠交付,以更好地满足业务需求和客户期望。具体来说,DevOps 旨在缩短软件的交付…...

《Somewhat Practical Fully Homomorphic Encryption》笔记 (BFV 源于这篇文章)

文章目录 一、摘要二、引言1、FHE 一般分为三个逻辑部分2、噪声的管理3. 贡献点4. 文章思路 三、基础数学知识四、基于 RLWE 的加密1. LWE 问题2. RLWE 问题3. RLWE 问题的难度和安全性 五、加密方案1. LPR.ES 加密方案2. Lemma 1 (引理 1)3. Optimisation/Assumption 1 (优化/…...

SpringBoot 2 后端通用开发模板搭建(异常处理,请求响应)

目录 一、环境准备 二、新建项目 三、整合依赖 1、MyBatis Plus 数据库操作 2、Hutool 工具库 3、Knife4j 接口文档 4、其他依赖 四、通用基础代码 1、自定义异常 2、响应包装类 3、全局异常处理器 4、请求包装类 5、全局跨域配置 补充&#xff1a;设置新建类/接…...

DeepSeek本地部署与Dify结合创建私有知识库指南

python调用本地deepseek+Dify的API使用--测试WX自动发送信息-CSDN博客 DeepSeek,一家在人工智能领域具有显著技术实力的公司,凭借其千亿参数规模的AI大模型,以及仅需0.5元人民币即可进行百万tokens的API调用成本,已经取得了令人瞩目的成就。不仅如此,DeepSeek的模…...

Nginx 报错:413 Request Entity Too Large

做web开发时&#xff0c;对于上传附件的功能&#xff0c;如果nginx没有调整配置&#xff0c;上传大一点的文件就会发生下面这种错误&#xff1a; 要解决上面的问题&#xff0c;只需要调整Nginx配置文件中的 client_max_body_size 参数即可&#xff0c;这个配置参数一般在http配…...

Arduino项目实战:使用MQ-2气体传感器与OLED屏幕监测环境气体

概述 在这个项目中,MQ-2气体传感器是一个多功能的气体检测设备,能够感知多种常见气体,如甲烷、丁烷、丙烷、酒精和烟雾等。你可以把它想象成一个超级灵敏的“嗅觉”,能够帮助你实时检测环境中的各种有害气体。与Arduino板连接后,MQ-2传感器把捕捉到的气体浓度数据传送给A…...

泛微Ecode新增Button调用服务器中的JSP页面里的方法

前言 前端Ecode调用 后端接口编写 JSP文件方法 总结 前言 因为我们是从之前E8版本升级到E9的&#xff0c;所以会有一些接口是通过jsp文件来实现前后端调用的&#xff0c;这里介绍的就是如果你有接口是写在jsp文件里面调用的&#xff0c;但是你又想在Ecode中调用的对应的接…...

C#实现本地Deepseek模型及其他模型的对话

前言 1、C#实现本地AI聊天功能 WPFOllamaSharpe实现本地聊天功能,可以选择使用Deepseek 及其他模型。 2、此程序默认你已经安装好了Ollama。 在运行前需要线安装好Ollama,如何安装请自行搜索 Ollama下载地址&#xff1a; https://ollama.org.cn Ollama模型下载地址&#xf…...

【ESP32S3接入讯飞在线语音识别】

视频地址: 【ESP32S3接入讯飞在线语音识别】 1. 前言 使用Seeed XIAO ESP32S3 Sense开发板接入讯飞实现在线语音识别。自带麦克风模块用做语音输入,通过串口发送字符“1”来控制数据的采集和上传。 语音识别对比 平台api教程评分百度...

【51单片机】快速入门

动手实践 > 理论空谈&#xff01;从点亮LED开始&#xff0c;逐步扩展功能&#xff0c;2周可入门基础。 一、51单片机基础概念 什么是51单片机&#xff1f; 基于Intel 8051架构的8位微控制器&#xff0c;广泛用于嵌入式开发。 核心特性&#xff1a;4KB ROM、128B RAM、32个…...

leetcode707----设计链表【链表增删改打印等操作】

目录 一、题目介绍 二、单链表 2.1 创建链表类 2.1.1 定义链表节点结构体代码块 2.1.2 MyLinkedList类的构造函数 2.1.3 私有成员变量 2.2 接口1&#xff1a;获取第下标为index的节点的值 2.3 接口2&#xff1a;头部插入节点 2.4 接口3&#xff1a;尾部插入节点 2.5 接…...

【问题记录】Go项目Docker中的consul访问主机8080端口被拒绝

【问题记录】Go项目Docker中的consul访问主机8080端口被拒绝 问题展示解决办法 问题展示 在使用docker中的consul服务的时候&#xff0c;通过命令行注册相应的服务&#xff08;比如cloudwego项目的demo_proto以及user服务&#xff09;失败。 解决办法 经过分析&#xff0c;是…...

【缓存】缓存雪崩与缓存穿透:高并发系统的隐形杀手

缓存雪崩与缓存穿透&#xff1a;高并发系统的隐形杀手 在高并发系统中&#xff0c;缓存是提升性能的重要手段。然而&#xff0c;缓存使用不当也会带来一系列问题&#xff0c;其中最常见的就是缓存雪崩和缓存穿透。这两个问题如果不加以解决&#xff0c;可能会导致系统崩溃&…...

网络协议 HTTP、HTTPS、HTTP/1.1、HTTP/2 对比分析

1. 基本定义 HTTP&#xff08;HyperText Transfer Protocol&#xff09; 应用层协议&#xff0c;用于客户端与服务器之间的数据传输&#xff08;默认端口 80&#xff09;。 HTTP/1.0&#xff1a;早期版本&#xff0c;每个请求需单独建立 TCP 连接&#xff0c;效率低。HTTP/1.1&…...

DeepSeek实现FunctionCalling调用API查询天气

什么是FunctionCalling Function Calling&#xff08;函数调用&#xff09;是大型语言模型&#xff08;如 OpenAI 的 GPT 系列&#xff09;提供的一种能力&#xff0c;允许模型在生成文本的过程中调用外部函数或工具&#xff0c;以完成更复杂的任务。通过 Function Calling&am…...

从 Spring Boot 2 升级到 Spring Boot 3 的终极指南

一、升级前的核心准备 1. JDK 版本升级 Spring Boot 3 强制要求 Java 17 及以上版本。若当前项目使用 Java 8 或 11&#xff0c;需按以下步骤操作&#xff1a; 安装 JDK 17&#xff1a;从 Oracle 或 OpenJDK 官网下载&#xff0c;配置环境变量&#xff08;如 JAVA_HOME&…...

C#设计模式深度解析:经典实现与现代演进 ——基于《设计模式》的.NET技术实践

一、设计模式与C#语言特性融合 C#凭借其面向对象特性、泛型、委托/事件、LINQ等能力&#xff0c;为设计模式提供了更优雅的实现方式。以下通过典型模式展现其技术融合&#xff1a; 1. 工厂方法模式 泛型约束 public interface IProduct<T> where T : new() {void O…...

原子性(Atomicity)和一致性(Consistency)的区别?

原子性&#xff08;Atomicity&#xff09;和一致性&#xff08;Consistency&#xff09;是数据库事务ACID特性中的两个核心概念&#xff0c;虽然它们密切相关&#xff0c;但解决的问题和侧重点完全不同。原子性关注事务的操作完整性&#xff0c;而一致性关注数据的逻辑正确性。…...

windows设置暂停更新时长

windows设置暂停更新时长 win11与win10修改注册表操作一致 &#xff0c;系统界面不同 1.打开注册表 2.在以下路径 \HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings 右键新建 DWORD 32位值&#xff0c;名称为FlightSettingsMaxPauseDays 根据需求填写数…...

【Kimi】自动生成PPT-并支持下载和在线编辑--全部免费

【Kimi】免费生成PPT并免费下载 用了好几个大模型&#xff0c;有些能生成PPT内容&#xff1b; 有些能生成PPT&#xff0c;但下载需要付费&#xff1b; 目前只有Kimi生成的PPT&#xff0c;能选择模板、能在线编辑、能下载&#xff0c;关键全部免费&#xff01; 一、用kimi生成PP…...

一款在手机上制作电子表格

今天给大家分享一款在手机上制作电子表格的&#xff0c;免费好用的Exce1表格软件&#xff0c;让工作变得更加简单。 1 软件介绍 Exce1是一款手机制作表格的办公软件&#xff0c;您可以使用手机exce1在线制作表格、工资表、编辑xlsx和xls表格文件等&#xff0c;还可以学习使用…...

【实战 ES】实战 Elasticsearch:快速上手与深度实践-1.3.1单节点安装(Docker与手动部署)

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 10分钟快速部署Elasticsearch单节点环境1. 系统环境要求1.1 硬件配置推荐1.2 软件依赖 2. Docker部署方案2.1 部署流程2.2 参数说明2.3 性能优化建议 3. 手动部署方案3.1 安…...

7 天精通 DeepSeek 实操手册

挑战目标 从零基础开始&#xff0c;用 7 天时间&#xff0c;精通 DeepSeek 实操。 对零基础的同学来说&#xff0c;要全部完成这个挑战并不容易。因此&#xff0c;我们提供了每天的学习目标和实操任务&#xff0c;并提供三大锦囊助你一臂之力&#xff1a; 针对常见问题的解决…...

过滤器 二、过滤器详解

过滤器生命周期&#xff1a; init(FilterConfig)&#xff1a;在服务器启动时会创建Filter实例&#xff0c;并且每个类型的Filter只创建一个实例&#xff0c;从此不再创建&#xff01;在创建完Filter实例后&#xff0c;会马上调用init()方法完成初始化工作&#xff0c;这个方法…...

【Mac电脑本地部署Deepseek-r1:详细教程与Openwebui配置指南】

文章目录 前言电脑配置&#xff1a;安装的Deepseek版本&#xff1a;使用的UI框架&#xff1a;体验效果展示&#xff1a;本地部署体验总结 部署过程Ollama部署拉取模型运行模型Openwebui部署运行Ollama服务在Openwebui中配置ollama的服务 后话 前言 deepseek最近火的一塌糊涂&a…...

网络安全学习中,web渗透的测试流程是怎样的?

渗透测试是什么&#xff1f;网络安全学习中&#xff0c;web渗透的测试流程是怎样的&#xff1f; 渗透测试就是利用我们所掌握的渗透知识&#xff0c;对网站进行一步一步的渗透&#xff0c;发现其中存在的漏洞和隐藏的风险&#xff0c;然后撰写一篇测试报告&#xff0c;提供给我…...

将VsCode变得顺手好用(1

目录 设置中文 配置调试功能 提效和增强相关插件 主题和图标相关插件 创建js文件 设置中文 打开【拓展】 输入【Chinese】 下载完成后重启Vs即可变为中文 配置调试功能 在随便一个位置新建一个文件夹&#xff0c;用于放置调试文件以及你未来写的代码&#xff0c;随便命名但…...