Lucene学习

Lucene---全文检索(文档pdf/txt/office/html) NULL 博文链接:https://wuquanyin1011.iteye.com/blog/799342 立即下载

一、什么是全文检索?

全文检索首先将要查询的目标文档中的词提取出来,组成索引(相当于书的目录),通过查询索引达到搜索目标文档的目的。这种先建立索引,再对索引进行搜索的过程就叫全文检索。

二、安装 Lucene

官网安装后解压;jdk要求:1.7以上

三、建立索引

在这里插入图片描述
在这里插入图片描述

四、查询索引

在这里插入图片描述
在这里插入图片描述

五、案例引导

(一)获取到原始内容【信息采集】
(二)创建文档

创建原始内容的目的是为了索引,在索引钱需要将原始内容创建成文档,文档中包含一个一个的域【field】,域中存储内容;
这里我们可以将磁盘上的一个文件当成一个document,document中包含一些field【file_name文件名称、file_path文件路径、file_size文件大小、file_content文件内容】;

(三)分析文档

将原始内容创建为包含域【field】的文档,需要对域中的内容进行分析,分析的过程是经过对原始文档提取单词、将字母转为小写、去除标点符号、去除停用词等过程生成最终的语汇单元【语汇单元理解为一个一个的单词】。

(四)索引文档

对所有文档分析得出的语汇单元进行索引,索引的目的是为了搜索,最终要实现只搜索被索引的语汇单元从而找到document;
注意: 创建索引是对语汇单元索引,通过词语找文档,这种索引的结构叫倒排索引结构
传统方法是根据文件找到该文件的内容,在文件内容中匹配搜索关键字,这种方法是顺序扫描方法,数据量大、搜索慢。

六、Lucene入门程序

1、开发环境

jdk:1.7 Lucene包【Lucene-core-5.2.jar、Lucene-analyzers-common-5.2.jar、lucene-queryparser-5.2.jar】 其他包【commons-io-2.4.jar、junit-4.9.jar】

2、创建数据源目录

该目录存放要搜索的原始文件。

3、创建索引目录

该目录存放创建的索引文件

4、Field常用类型

下面列出了开发中常用的field类型,注意field的属性,并根据需求选择:
在这里插入图片描述
在这里插入图片描述

5、代码实现–导入索引
public void importIndex() throws IOException {
	//获得索引库
	Path path = Paths.get("D:\\java\\Luence\\index_io");
	//打开索引库
	FSDirectory dir = FSDirectory.open(path);
	//创建分词器
	Analyzer al = new IKAnalyzer();
	//创建索引的写入配置对象
	IndexWriterConfig iwc = new IndexWriterConfig(al);
	//创建索引的Writer
	IndexWriter iw = new IndexWriter(dir, iwc);
	
	//采集原始文档
	File files = new File("D:\\java\\Luence\\searchsource");
	//获得文件夹下的所有文件
	File[] file = files.listFiles();
	//遍历每一个文件
	for(File fl : file) {
		//获得文件的属性
		String fileName = fl.getName();
		String content = FileUtils.readFileToString(fl);
		//获得文件大小
		long size = FileUtils.sizeOf(fl);
		//获取路径
		String path1 = fl.getPath();	
		
		Field fName = new TextField("fileName", fileName, Store.YES);
		Field fcontent = new TextField("content", content, Store.YES);
		Field fsize = new LongField("size", size, Store.YES);
		Field fpath = new TextField("path", path1, Store.YES);
		
		//创建文档对象
		Document doc = new Document();
		//把域加入到文档中
		doc.add(fName);
		doc.add(fcontent);
		doc.add(fsize);
		doc.add(fpath);
		//把文档写入到索引库
		iw.addDocument(doc);
		
	}
	//提交
	iw.commit();
	//关闭资源
	iw.close();
}

七、Luke

Luke作为Lucene工具包中的一个工具,用于查询、修改Lucene的索引文件。
打开luke的方法: cmd运行: java -jar lukeall-4.10.3.jar
如果需要加载第三方分词器,如果需要加载第三方分词器,需通过java.ext.dirs加载jar包:可简单的将第三方分词器和lukeall放在一块儿,cmd下运行:java -Djava.ext.dirs=. -jar lukeall-4.10.3.jar

7.1使用luke查看索引

在这里插入图片描述

八、Analyzer分词器

8.1创建索引时使用Analyzer

输入关键字进行搜索,当需要让该关键字与文档域内容所包含的词进行匹配时需要对文档域内容进行分析,需要经过Analyzer分析器处理生成语汇单元(Token).分词器分析的对象是文档中的field。当field的属性tokenized(是否分词)为true时会对field值进行分析。
在这里插入图片描述
对于一些field课余不用分析:
①不作为查询条件的内容,比如文件路径;
②不是匹配内容中的词而匹配field的整体内容,比如订单号、身份证号等。

8.2Analyzer执行过程

Analyzer是一个抽象类,在Lucene的lucene-analyzers-common包中提供了很多分析器,比如:org.apache.lucene.analysis.standard.standardAnalyzer标准分词器,它是Lucene的核心分词器,它对分析文本进行分词、大写转成小写、去除停用词、去除标点符号等操作过程。
在这里插入图片描述
从一个Reader字符流开始,创建一个基于Reader的Tokenizer分词器,经过三个TokenFilter生成语汇单元Token.

8.3 TokenStream

TokenStream是语汇单元流,tokenStream是一个抽象类,它是所有分析器的基类;
TokenStream是分词器,负责将Reader转换为语汇单元即进行分词,Lucene提供了很多的分词器,也可以使用第三方的分词,比如IKAnalyzer一个中文分词器。
tokenFileter是分词过滤器,负责对语汇单元进行过滤,tokenfilter可以是一个过滤器链儿,Lucene提供了很多的分词器过滤器,比如大小写转换,去除停用词等。

8.4 分词器的使用
@Test
public void importAnalyzer() throws IOException {
	//创建分词器
	//Analyzer al = new StandardAnalyzer();
	//Analyzer al = new CJKAnalyzzer();
	Analyzer al = new IKAnalyzer();
	//分词
	TokenStream stream = al.tokenStream("content", "Serving Web Content with Spring mvc 中国红太阳升红红火火恍恍惚惚明明白白");
	//分词对象的重置
	stream.reset();
	//获得每一个语汇的偏移量的属性对象
	OffsetAttribute oa = stream.addAttribute(OffsetAttribute.class);
	//获得分词的语汇属性
	CharTermAttribute ca = stream.addAttribute(CharTermAttribute.class);
	//遍历分词的语汇流
	while(stream.incrementToken()) {
		System.out.println("----------------");
		System.out.println("开始索引:"+oa.startOffset()+"结束索引:"+oa.endOffset());
		System.out.println(ca);
	}
}

九、索引维护

9.1添加索引

步骤: (1)创建存放索引的目录Directory;(2)创建索引器配置管理类IndexWriterConfig;(3)使用索引目录和配置管理类创建索引器;(4)使用索引器将Document写到索引文件中;

	@Test
	public void importIndex() throws IOException {
		IndexWriter iw = getIndexWriter();
		
		//采集原始文档
		File fl = new File("D:\\java\\Luence\\searchsource\\hibernate.txt");
		//获得文件的属性
		String fileName = fl.getName();
		String content = FileUtils.readFileToString(fl);
		//获得文件大小
		long size = FileUtils.sizeOf(fl);
		//获取路径
		String path1 = fl.getPath();	
		//域
		Field fName = new TextField("fileName", fileName, Store.YES);
		Field fcontent = new TextField("content", content, Store.YES);
		Field fsize = new LongField("size", size, Store.YES);
		Field fpath = new TextField("path", path1, Store.YES);
		
		//创建文档对象
		Document doc = new Document();
		//把域加入到文档中
		doc.add(fName);
		doc.add(fcontent);
		doc.add(fsize);
		doc.add(fpath);
		//把文档写入到索引库
		iw.addDocument(doc);
		
		//提交
		iw.commit();
		//关闭资源
		iw.close();
	}
	public IndexWriter getIndexWriter() throws IOException {
		//获得索引库
		Path path = Paths.get("D:\\java\\Luence\\index_io");
		//打开索引库
		FSDirectory dir = FSDirectory.open(path);
		//创建分词器
		Analyzer al = new StandardAnalyzer();
		//创建索引的写入配置对象
		IndexWriterConfig iwc = new IndexWriterConfig(al);
		//创建索引的Writer
		IndexWriter iw = new IndexWriter(dir, iwc);
		return iw;
	}
9.2删除索引
	@Test
	public void deleteIndex() throws IOException {
		IndexWriter iw = getIndexWriter();
		//删除所有
		iw.deleteAll();
		//提交
		iw.commit();
		//关闭
		iw.close();
	}
	@Test
	public void deleteIndexByQuery() throws Exception {
		IndexWriter iw = getIndexWriter();
		//创建语汇单元项
		Term term = new Term("fileName","spring");
		//创建根据语汇单元的查询对象
		TermQuery query = new TermQuery(term);
		iw.deleteDocuments(query);
		//提交
		iw.commit();
		//关闭
		iw.close();
	}
9.3增加索引(一)
	@Test
	public void queryIndex() throws IOException {
		//获得索引库
		Path path = Paths.get("D:\\java\\Luence\\index_io");
		FSDirectory open = FSDirectory.open(path);
		//创建索引库的读取对象
		DirectoryReader reader = DirectoryReader.open(open);
		//创建索引库的搜索对象
		IndexSearcher is = new IndexSearcher(reader);
		//创建语汇单元的对象
		Term term = new Term("fileName","教育");
		//创建分词的语汇查询对象
		TermQuery tq = new TermQuery(term);
		//查询
		TopDocs result = is.search(tq, 10);
		//总记录数
		int totalHits = result.totalHits;
		System.out.println(totalHits);	
		
		for(ScoreDoc sd:result.scoreDocs) {
			//获得文档的id
			int id = sd.doc;
			//获得文档对象
			Document doc = is.doc(id);
			String fileName = doc.get("fileName");
			String size = doc.get("size");
			String content = doc.get("content");
			String path1 = doc.get("path");
			System.out.println("文件名:"+fileName);
			System.out.println("大小:"+size);
			System.out.println("内容:"+content);
			System.out.println("路径:"+path1);
			System.out.println("-------------------------");
		}		
	}
9.4增加索引(二)

通过Query搜索
NumericRangeQuery,指定数字范围查询,如下://文件大小在0到1024的文件

	@Test
	public void queryIndex() throws Exception {
		IndexSearcher is = getDirReader();
		//创建语汇单元的对象
		//Term term = new Term("fileName","教育");
		//创建分词的语汇查询对象
		//TermQuery tq = new TermQuery(term);
		//创建数值范围查询对象  注意0l和100l最后一位都是小写的L
		Query tq = NumericRangeQuery.newLongRange("size", 0l, 100l, true, true);
		System.out.println(tq);
		printDoc(is, tq);
		
	}
	public static IndexSearcher getDirReader() throws Exception {
		//获得索引库
		Path path = Paths.get("D:\\java\\Luence\\index_io");
		FSDirectory open = FSDirectory.open(path);
		//创建索引库的读取对象
		DirectoryReader reader = DirectoryReader.open(open);
		//创建索引库的搜索对象
		IndexSearcher is = new IndexSearcher(reader);
		return is;
	}
	public static void printDoc(IndexSearcher is,Query tq) throws Exception {
		//查询
		TopDocs result = is.search(tq, 10);
		//总记录数
		int totalHits = result.totalHits;
		System.out.println(totalHits);	
		
		for(ScoreDoc sd:result.scoreDocs) {
			//获得文档的id
			int id = sd.doc;
			//获得文档对象
			Document doc = is.doc(id);
			String fileName = doc.get("fileName");
			String size = doc.get("size");
			String content = doc.get("content");
			String path1 = doc.get("path");
			System.out.println("文件名:"+fileName);
			System.out.println("大小:"+size);
			System.out.println("内容:"+content);
			System.out.println("路径:"+path1);
			System.out.println("-------------------------");
		}
	}
9.5增加索引(三)QueryParser查询

QueryParser使用方法:

//f是默认搜索的域
QueryParser queryParser = new QueryParser("f", analyzer);
// 指定查询语法 ,如果不指定fileName就搜索默认的域
Query query2 = queryParser.parse("fileName:springmvc.txt");
或者
Query query2 = queryPArser.parse("spring AND web");

案例:

	@Test
	public void queryIndex2() throws Exception {
		IndexSearcher is = getDirReader();
		//创建分词器
		Analyzer al = new IKAnalyzer();
		//创建查询解析器
		QueryParser qp = new QueryParser("fileName", al);
		//通过qp来解析查询对象
		Query query = qp.parse("今天我们来学习全文检索技术Lucene");
		System.out.println("打印查询条件:"+query);
		printDoc(is, query);
	}
	@Test
	public void queryIndex3() throws Exception {
		IndexSearcher is = getDirReader();
		//创建分词器
		Analyzer al = new IKAnalyzer();
		//创建查询解析器
		QueryParser qp = new QueryParser("fileName", al);
		//通过qp来解析查询对象
		Query query = qp.parse("fileName:solr OR content:java");
		System.out.println("打印查询条件:"+query);
		printDoc(is, query);
	}
9.6MultiFieldQueryParser组合域查询

通过MuliFieldQueryParse对多个域查询,比如商品信息查询,输入关键字需要从商品名称和商品内容中查询。

	@Test
	public void queryIndex5() throws Exception {
		IndexSearcher is = getDirReader();
		//创建分词器
		Analyzer al = new IKAnalyzer();
		
		//定义多个域
		String[] fields = {"fileName","content"};
		//创建查询解析对象
		MultiFieldQueryParser mp = new MultiFieldQueryParser(fields, al);
		Query query = mp.parse("今天我们学习全文检索技术Lucene");
		
		Query tq = NumericRangeQuery.newLongRange("size", 0l, 1024l, true, true);
		BooleanQuery bq = new BooleanQuery();
		bq.add(query, Occur.MUST);
		bq.add(tq, Occur.MUST);
		
		System.out.println("打印查询条件:"+bq);
		printDoc(is, bq);
	}
高通thermal-engine.conf配置详解:从虚拟传感器到CPU频率控制的完整指南 本文深入解析了高通thermal-engine.conf配置文件的架构与调优方法。从虚拟传感器的加权融合原理,到监控算法与CPU频率控制的多级策略,提供了完整的配置详解与实战调试指南。文章旨在帮助开发者与高级用户掌握底层温控逻辑,在性能与散热间实现精准平衡,并详细介绍了日志调试与场景化配置等高级技巧。 阅读详情

相关推荐

检索生成(RAG) vs 长文本大模型:实际应用中如何选择?

大模型的上下文理解能力直接影响到 LLMs 在复杂任务和长对话中的表现。本期内容聚焦于两种主流技术:长上下文(Large Context Windows)和检索增强生成(RAG)。这两种技术各有何优势?在实际应用中,我们又该如何权衡选择?文章不仅详细阐述了这两种技术的工作原理,还深入分析了它们在效率、准确性和实施成本等方面的差异。文章特别提到了在执行重复性任务时使用 Context Caching 优化长上下文的优势,然而,缓存策略的效果很大程度上取决于提示词的可预测性。

2401_85782938的博客 1255

搜索引擎之Lucene

1 Lucene介绍 1.1 什么是Lucene Lucene是apache下的一个开源的全文检索引擎工具包。它为软件开发人员提供一个简单易用的工具包(类库),以方便的在目标系统中实现全文检索的功能。 1.2 全文检索的应用场景 1.2.1 搜索引擎 ©注意: Lucene和搜索引擎是不同的,Lucene是一套用java或其它语言写的全文检索的工...

oldmonk 198

别再只跑Demo了!用MovieLens数据集完整复现一个电影推荐系统(Python/Pandas实战)

本文详细介绍了如何利用MovieLens数据集从零构建一个完整的电影推荐系统,涵盖数据清洗、特征工程、推荐算法实现(协同过滤和矩阵分解)以及Web服务部署的全流程。通过Python和Pandas实战,读者可以掌握推荐系统的核心技术和生产环境部署技巧,不再局限于简单的Demo运行。

weixin_29062865的博客 150

Lucene从入门到精通

-三方分词器****************************************************************************************************************************************************-->Product product_1 = new Product(1, "华为手机", 3000, 10, "华为.jpg", "华为", "300*300", 5);

p6448777的博客 1428

海量数据 / Vastbase 深度研究笔记 v3.1

v3.1 重点修订:在 v3.0 审慎版基础上,新增“2026 新变量”章节,纳入 7 亿级定增、HTAP / 多模态时序数据库、G100 V3.0 Build 8 的 3CM+2DN 高可用补强、pgvector / V100 / AI 多模叙事,以及集成服务基因与标准软件 ARR 的拉扯。核心关注点是:Vastbase 能否把 openGauss 生态红利、数据库产品矩阵和行业交付能力,转化为可持续、可复购、低边际成本的标准软件收入。海量不是没有业务基本盘,也不是马上失血致死;客户越多,服务债越大。

喝醉酒的小白 562

VS2022离线安装总闪退?可能是这个--noWeb参数没加对(完整参数指南)

本文深入解析了VS2022离线安装过程中常见的闪退问题,指出核心原因往往在于命令行参数使用不当,特别是`--noWeb`参数。文章提供了完整的参数使用指南和实战解决方案,包括证书处理、安装器文件修复及自动化脚本,帮助用户彻底解决离线部署中的验证失败与闪退难题。

weixin_28842269的博客 758

Java轻量级全文检索引擎Lucene使用及优化

Lucene是一个开源的全文检索引擎工具包由Doug Cutting编写。它被设计用于实现全文搜索功能,即读入一堆文本文件并将其转换为易于搜索的数据结构。Lucene提供了一组简单而强大的API,使得索引和搜索过程变得非常方便。

BXA 5964

c语言压力变送器程序设计,基于单片机的压力变送器设计

基于单片机的压力变送器设计(任务书,开题报告,外文翻译,论文15000字,代码)摘要随着工业化水平的不断提高,新型智能仪表在工业生产过程中运用也越来越广泛,同时对输出数据的准确检测和处理也变得至关重要。生产过程的运行和设备安全是极其重要的,那么如何实现对其精确的检测呢?众所周知,在工业生产过程中有一个很重要参数——压力,显然这个参数是一个必不可少的条件。故而,研究智能压力变松器系统对工业生产有着不...

weixin_33681561的博客 1963

啥?你不知道Lucene,这份高级学习文档你值得拥有

计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。什么是全文检索什么是LuceneLucene官网。

m0_57042151的博客 314

大麦APP抢票协议分析:从‘掌密网络’代码看移动端API安全防护

本文深度解析了大麦APP抢票协议的安全防护体系,重点分析了'掌密网络'代码中体现的动态签名、设备指纹和人机验证等关键技术。文章详细介绍了大麦APP如何通过多层次API安全防护应对抢票压力,包括参数加密、请求头部设计和异常处理机制,为移动应用开发者提供了安全实践建议。

weixin_28740299的博客 290

【100%通过率】2024华为OD机试真题E卷 C++语言 实现【流浪地球】

流浪地球计划在赤道上均匀部署了N个转向发动机,按位置顺序编号为0~N-1。 1) 初始状态下所有的发动机都是未启动状态; 2) 发动机起动的方式分为“手动启动”和“关联启动”两种方式; 3) 如果在时刻1一个发动机被启动,下一个时刻2与之相邻的两个发动机就会被“关联启动”; 4) 如果准备启动某个发动机时,它已经被启动了,则什么都不用做; 5) 发动机0与发动机N-1是相邻; 地球联合政府准备挑选某些发动机在某些时刻进行“手动启动”,当然最终所有的发动机都会被启动。 哪些发动机最晚被启动呢?

MISAYAONE的博客 4212

【Lucene】原理学习路线

基于《Lucene原理与代码分析完整版》,制定了一个系统学习Lucene原理的计划,并将每个阶段的学习内容组织成专栏文章,zero2hero 手搓 Lucene的核心概念和实现细节。

weiliang_Handan的博客 1071

【FPGA教程案例100】深度学习1——基于CNN卷积神经网络的手写数字识别纯Verilog实现,使用mnist手写数字数据库

MNIST 数据库有一个 60,000 示例的训练集,还有一个 10,000 示例的测试集。这些数字已在大小方面规范化,在固定大小的图像中居中。如下图所示:我们任意选择0~9是个数字,将其转化为数字:0_0.txt1_0.txt2_0.txt3_0.txt4_0.txt5_0.txt6_0.txt7_0.txt8_0.txt9_0.txt。

FPGA/MATLAB学习教程/源码/项目合作开发 7830

lucene学习总结之_学习Lucene

lucene学习总结之 我目前正在与一个团队合作,开始一个基于Lucene的新项目。 虽然大多数时候我会争论使用Solr还是Elasticsearch而不是简单的Lucene,但这是一个有意识的决定。 在这篇文章中,我正在整理一些学习Lucene的资料–希望您会发现它们对您有所帮助,或者可以提示我错过了哪些资料。 项目文件 当然,首选的是出色的项目文档。 它包含所有模块的Javadoc(最重要的...

cunhu2961的博客 181

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

有时间学习一下LUCENE

有时间学习一下LUCENE

woyaoyiwanyuexin的博客 135

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

学习Lucene

我目前正在与一个团队合作,开始一个基于Lucene的新项目。 虽然大多数时候我会争论使用Solr还是Elasticsearch而不是简单的Lucene,但这是一个有意识的决定。 在这篇文章中,我正在整理一些学习Lucene的资源–希望您对他们有所帮助,或者可以提示我错过了哪些资源。 项目文件 当然,首选的是出色的项目文档 。 它包含所有模块的Javadoc(最重要的模块是core , a...

最佳 Java 编程 143

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

lucene学习笔记_学习Lucene

lucene学习笔记 我目前正在与一个团队合作,开始一个基于Lucene的新项目。 虽然大多数时候我会争论使用Solr还是Elasticsearch而不是简单的Lucene,但这是一个有意识的决定。 在这篇文章中,我正在整理一些学习Lucene的资源–希望您对他们有所帮助,或者可以提示我错过了哪些资源。 项目文件 当然,首选的是出色的项目文档 。 它包含所有模块的Javadoc(最重要的模...

最佳 Java 编程 163

Lucene学习极好的博客

http://qindongliang.iteye.com/blog/1913565

十年饮冰,难凉热血 832

Lucene学习笔记整理

因为项目的要求,自学Lucene接近一个月的时间,期间由

Free_Dou的专栏 846

lucene学习之说在前面的话

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34202952的博客 82

Lucene学习总结

Lucene学习总结

mpk_no1的博客 624

Lucene 及 Lucene.net 国内外的一些学习资源汇总

目前互联网上关于Lucene 及 Lucene.net 的文章很多,看了一些,感觉绝大部分还是偏向于应用,真正深入探讨其核心算法的文章不是太多,最近打算深入研究一下Lucene.net,把一些关键技术点的核心算法搞清楚。在开始做这个工作之前,先对目前互联网上可以利用的资源做个汇总,算是抛砖引玉吧,还望网友们多来补充,大家共同学习! lucene 官方网站, Luncene.net 官方网站(英文)...

绝影メ之殇 161

lucene学习资料

最近研究lucene整理下学习资料:

Java与咖啡 242

lucene学习资料(书籍、视频)

已经使用lucene好一段时间了,整理了一下学习资料,应该是最全的版本了, lucene学习资料(书籍、视频) 希望对后续学习lucene的同学们有所帮助。

shblaze的专栏 926
上一篇: Node学习(二)
下一篇: Node学习(三)
智汇风渔AI小白
博客等级 码龄7年 1万+粉丝 179原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智汇风渔AI小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值