java之全文索引搜索lucene之增删改查文档与中文分词搜索
java之全文索引搜索lucene之增删改查文档与中文分词搜索
接上文,接下来介绍一个lucene的各种query,然后介绍一下中文全文索引搜索。
对于各种query,我就直接上代码了,具体的话,我已经在代码里面注释了,而且关于lucene的执行流程在上文我也已经介绍过了,下面就不废话了。当然啦,我在这里使用过程采用的是java单元测试!
使用之前需要通过这么一些数据建立索引器,这些数据可以来这里下载:,下载之后放到D:\\lucene-exercise\\data文件夹下。然后通过下面这段代码建立索引:
package com.steadyjack.lucene01;import java.io.File;
import java.io.FileReader;
import java.nio.file.Paths;import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;public class Indexer {//写实例private IndexWriter writer;/*** ʵ初始化写实例* @param indexDir*/public Indexer(String indexDir)throws Exception{Directory dir=FSDirectory.open(Paths.get(indexDir));//标准分词器Analyzer analyzer=new StandardAnalyzer();IndexWriterConfig iwc=new IndexWriterConfig(analyzer);writer=new IndexWriter(dir, iwc);}/*** Description:关闭写实例* Date:2017年2月24日 下午9:40:36* Author:debug-steadyjack* @throws Exception*/public void close()throws Exception{writer.close();}/*** Description:建立索引* Author:debug-steadyjack* @param dataDir* @return* @throws Exception*/public int index(String dataDir)throws Exception{File[] files=new File(dataDir).listFiles();for(File f:files){IndexFile(f);}return writer.numDocs();}private void IndexFile(File f)throws Exception {System.out.println("文件全路径: "+f.getCanonicalPath());Document doc=getDocument(f);writer.addDocument(doc);}private Document getDocument(File f)throws Exception{Document doc=new Document();doc.add(new TextField("contents",new FileReader(f)));//TextField一般则表示需要进行分词存储doc.add(new TextField("fileName", f.getName(),Field.Store.YES));doc.add(new TextField("fullPath",f.getCanonicalPath(),Field.Store.YES));return doc;}public static void main(String[] args) {//建立的索引存放的目录-索引器目录String indexDir="D:\\lucene-exercise\\lucene4";//索引所需要的数据所在的目录String dataDir="D:\\lucene-exercise\\data";Indexer indexer=null;int numIndexed=0;long start=System.currentTimeMillis();try {indexer = new Indexer(indexDir);numIndexed=indexer.index(dataDir);} catch (Exception e) {e.printStackTrace();}finally{try {indexer.close();} catch (Exception e) {e.printStackTrace();}}long end=System.currentTimeMillis();System.out.println("一共写入了 "+numIndexed+" 个文档,用时:"+(end-start)+" 毫秒");}}
最终建立的索引目录如下:
下面先介绍一下对指定项进行搜索、对表达式进行搜索域分页搜索:
package com.steadyjack.lucene03;import java.nio.file.Paths;import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;/*** Description:测试搜索-特定项搜索,表达式搜索* Date:2017年2月22日 下午8:59:12* @author debug-steadyjack*/
public class TesSearchQueryParser {private Directory dir;private IndexReader reader;private IndexSearcher is;/*** Description:初始化读取索引器(索引所在地)* Date:2017年2月24日 下午10:09:57* Author:debug-steadyjack* @throws Exception*/@Beforepublic void before()throws Exception{dir=FSDirectory.open(Paths.get("D:\\lucene-exercise\\lucene4"));reader=DirectoryReader.open(dir);is=new IndexSearcher(reader);}@Afterpublic void after()throws Exception{reader.close();}/*** Description:对特定项进行查询-TermQuery* Date:2017年2月24日 下午10:10:59* Author:debug-steadyjack* @throws Exception*/@Testpublic void testTermQuery()throws Exception{String searchField="contents";String q="stempel";Term t=new Term(searchField, q);TermQuery query=new TermQuery(t);TopDocs hits=is.search(query, 10);System.out.println("搜索 "+q+" 匹配到了 "+hits.totalHits+" 个文档");for(ScoreDoc scoreDoc:hits.scoreDocs){Document document=is.doc(scoreDoc.doc);System.out.println(document.get("fullPath"));}}/*** Description:对表达式进行搜索-QueryParser需要进行分词* Date:2017年2月24日 下午10:11:35* Author:debug-steadyjack* @throws Exception*/@Testpublic void testQueryParser()throws Exception{String searchField="contents";String q="java";//标准分词器Analyzer a=new StandardAnalyzer();QueryParser parser=new QueryParser(searchField, a);Query query=parser.parse(q);TopDocs hits=is.search(query, 10);System.out.println("搜索 "+q+" 匹配到了 "+hits.totalHits+" 个文档");for(ScoreDoc scoreDoc:hits.scoreDocs){Document document=is.doc(scoreDoc.doc);System.out.println(document.get("fullPath"));}}/*** Description:模拟了分页搜索* Date:2017年2月24日 下午10:37:38* Author:debug-steadyjack* @throws Exception*/@Testpublic void testPagination()throws Exception{//第几页与每页需要显示的记录数int pageNo=2;int pageSize=2;String searchField="contents";String q="java";//标准分词器Analyzer a=new StandardAnalyzer();QueryParser parser=new QueryParser(searchField, a);Query query=parser.parse(q);TopDocs hits=is.search(query, 100);System.out.println("搜索 "+q+" 匹配到了 "+hits.totalHits+" 个文档");ScoreDoc[] scoreDocs=hits.scoreDocs;/** 搜索 java 匹配到了 7 个文档D:\lucene-exercise\data\SYSTEM_REQUIREMENTS.txtD:\lucene-exercise\data\JRE_VERSION_MIGRATION.txtD:\lucene-exercise\data\README.txtD:\lucene-exercise\data\NOTICE.txtD:\lucene-exercise\data\MIGRATE.txtD:\lucene-exercise\data\LICENSE.txtD:\lucene-exercise\data\CHANGES.txt */int pos=(pageNo-1)*pageSize;for(int i=pos;i<pos+pageSize;i++){ScoreDoc scoreDoc=scoreDocs[i];Document document=is.doc(scoreDoc.doc);System.out.println(document.get("fullPath"));}}}
下面介绍的则是另外存在的各种query:指定项范围搜索、指定数字范围搜索、指定字符串开头搜索:
首先是Indexer:建立索引器
package com.steadyjack.lucene04;import java.nio.file.Paths;import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;public class Indexer {private Integer ids[]={1,2,3};private String citys[]={"aingdao","banjing","changhai"};private String descs[]={"Qingdao is b beautiful city.","Nanjing is c city of culture.","Shanghai is d bustling city."};private Directory dir;/*** Description:获取IndexWriter实例* Date:2017年2月24日 下午10:54:38* Author:debug-steadyjack* @return* @throws Exception*/private IndexWriter getWriter()throws Exception{Analyzer analyzer=new StandardAnalyzer(); // 标准分词器IndexWriterConfig iwc=new IndexWriterConfig(analyzer);IndexWriter writer=new IndexWriter(dir, iwc);return writer;}/*** 生成索引* @param indexDir* @throws Exception*/private void index(String indexDir)throws Exception{dir=FSDirectory.open(Paths.get(indexDir));IndexWriter writer=getWriter();for(int i=0;i<ids.length;i++){Document doc=new Document();doc.add(new IntField("id", ids[i], Field.Store.YES));doc.add(new StringField("city",citys[i],Field.Store.YES));doc.add(new TextField("desc", descs[i], Field.Store.YES));writer.addDocument(doc); }writer.close();}public static void main(String[] args) throws Exception {new Indexer().index("D:\\lucene-exercise\\lucene5");}}
下面是各种query的测试:
package com.steadyjack.lucene04;import java.nio.file.Paths;import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermRangeQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.BytesRef;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;/*** Description:组合查询* Date:2017年2月24日 下午10:56:09* @author debug-steadyjack*/
public class SearchTest {private Directory dir;private IndexReader reader;private IndexSearcher is;@Beforepublic void before() throws Exception {dir=FSDirectory.open(Paths.get("D:\\lucene-exercise\\lucene5"));reader=DirectoryReader.open(dir);is=new IndexSearcher(reader);}@Afterpublic void after() throws Exception {reader.close();}/*** Description:指定项范围搜索 - 一般少用* Date:2017年2月24日 下午10:57:00* Author:debug-steadyjack* @throws Exception*/@Testpublic void testTermRangeQuery()throws Exception{//指定搜索域为 desc中 存在从 b开头到 c结尾 的内容的文件TermRangeQuery query=new TermRangeQuery("desc", new BytesRef("b".getBytes()), new BytesRef("c".getBytes()), true, true);TopDocs hits=is.search(query, 10);for(ScoreDoc scoreDoc:hits.scoreDocs){Document doc=is.doc(scoreDoc.doc);System.out.println(doc.get("id"));System.out.println(doc.get("city"));System.out.println(doc.get("desc"));} }/*** Description:指定数字范围* Date:2017年2月24日 下午10:57:42* Author:debug-steadyjack* @throws Exception*/@Testpublic void testNumericRangeQuery()throws Exception{//指定搜索域为 id中 存在从 1到2 的内容的文件NumericRangeQuery<Integer> query=NumericRangeQuery.newIntRange("id", 1, 2, true, true);TopDocs hits=is.search(query, 10);for(ScoreDoc scoreDoc:hits.scoreDocs){Document doc=is.doc(scoreDoc.doc);System.out.println(doc.get("id"));System.out.println(doc.get("city"));System.out.println(doc.get("desc"));} }/*** Description:指定字符串开头搜索* Date:2017年2月24日 下午10:58:58* Author:debug-steadyjack* @throws Exception*/@Testpublic void testPrefixQuery()throws Exception{//指定搜索域为 city中 存在前缀为a 的内容的文件PrefixQuery query=new PrefixQuery(new Term("city","a"));TopDocs hits=is.search(query, 10);for(ScoreDoc scoreDoc:hits.scoreDocs){Document doc=is.doc(scoreDoc.doc);System.out.println(doc.get("id"));System.out.println(doc.get("city"));System.out.println(doc.get("desc"));} }/*** Description:多条件查询(即组合查询) - 比较常用* Date:2017年2月24日 下午10:59:43* Author:debug-steadyjack* @throws Exception*/@Testpublic void testBooleanQuery()throws Exception{BooleanQuery.Builder booleanQuery=new BooleanQuery.Builder();NumericRangeQuery<Integer> query1=NumericRangeQuery.newIntRange("id", 1, 2, true, true);PrefixQuery query2=new PrefixQuery(new Term("city","a"));booleanQuery.add(query1,BooleanClause.Occur.MUST);booleanQuery.add(query2,BooleanClause.Occur.MUST);TopDocs hits=is.search(booleanQuery.build(), 10);for(ScoreDoc scoreDoc:hits.scoreDocs){Document doc=is.doc(scoreDoc.doc);System.out.println(doc.get("id"));System.out.println(doc.get("city"));System.out.println(doc.get("desc"));} }}
最后,我们介绍一下lucene的常用之处:中文分词全文索引与索引结果高亮显示
首先也是先建立Indexer:索引器
package com.steadyjack.lucene05;import java.nio.file.Paths;import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;public class Indexer {private Integer ids[]={1,2,3};private String citys[]={"青岛","南京","上海"};private String descs[]={"青岛是一个美丽的城市。","南京是一个有文化的城市。南京是一个文化的城市南京,简称宁,是江苏省会,地处中国东部地区,长江下游,濒江近海。全市下辖11个区,总面积6597平方公里,2013年建成区面积752.83平方公里,常住人口818.78万,其中城镇人口659.1万人。[1-4] “江南佳丽地,金陵帝王州”,南京拥有着6000多年文明史、近2600年建城史和近500年的建都史,是中国四大古都之一,有“六朝古都”、“十朝都会”之称,是中华文明的重要发祥地,历史上曾数次庇佑华夏之正朔,长期是中国南方的政治、经济、文化中心,拥有厚重的文化底蕴和丰富的历史遗存。[5-7] 南京是国家重要的科教中心,自古以来就是一座崇文重教的城市,有“天下文枢”、“东南第一学”的美誉。截至2013年,南京有高等院校75所,其中211高校8所,仅次于北京上海;国家重点实验室25所、国家重点学科169个、两院院士83人,均居中国第三。[8-10] 。","上海是一个繁华的城市。"};private Directory dir;/*** Description:获取IndexWriter实例* Date:2017年2月24日 下午11:04:21* Author:debug-steadyjack* @return* @throws Exception*/private IndexWriter getWriter()throws Exception{//Analyzer analyzer=new StandardAnalyzer(); // 标准分词器SmartChineseAnalyzer analyzer=new SmartChineseAnalyzer(); //中文分词器IndexWriterConfig iwc=new IndexWriterConfig(analyzer);IndexWriter writer=new IndexWriter(dir, iwc);return writer;}/*** Description:生成索引* Date:2017年2月24日 下午11:05:57* Author:debug-steadyjack* @param indexDir* @throws Exception*/private void index(String indexDir)throws Exception{dir=FSDirectory.open(Paths.get(indexDir));IndexWriter writer=getWriter();for(int i=0;i<ids.length;i++){Document doc=new Document();doc.add(new IntField("id", ids[i], Field.Store.YES));doc.add(new StringField("city",citys[i],Field.Store.YES));doc.add(new TextField("desc", descs[i], Field.Store.YES));writer.addDocument(doc);}writer.close();}public static void main(String[] args) throws Exception {new Indexer().index("D:\\lucene-exercise\\lucene6");}}
然后是中文分词搜索与搜索结果高亮显示Searcher:
package com.steadyjack.lucene05;import java.io.StringReader;
import java.nio.file.Paths;import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.Fragmenter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.search.highlight.SimpleSpanFragmenter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;/*** Description:中文分词 与 搜索结果高亮显示* Date:2017年2月24日 下午11:03:57* @author debug-steadyjack*/
public class Searcher {/*** Description:搜索* Date:2017年2月24日 下午11:06:45* Author:debug-steadyjack* @param indexDir* @param q* @throws Exception*/public static void search(String indexDir,String q)throws Exception{Directory dir=FSDirectory.open(Paths.get(indexDir));IndexReader reader=DirectoryReader.open(dir);IndexSearcher is=new IndexSearcher(reader);// Analyzer analyzer=new StandardAnalyzer(); // 标准分词器SmartChineseAnalyzer analyzer=new SmartChineseAnalyzer();QueryParser parser=new QueryParser("desc", analyzer);Query query=parser.parse(q);long start=System.currentTimeMillis();TopDocs hits=is.search(query, 10);long end=System.currentTimeMillis();System.out.println("匹配 "+q+" ,总共花费"+(end-start)+"毫秒"+"查询到"+hits.totalHits+"个记录");//下面是高亮显示QueryScorer scorer=new QueryScorer(query);Fragmenter fragmenter=new SimpleSpanFragmenter(scorer);SimpleHTMLFormatter simpleHTMLFormatter=new SimpleHTMLFormatter("<b><font color='red'>","</font></b>");Highlighter highlighter=new Highlighter(simpleHTMLFormatter, scorer);highlighter.setTextFragmenter(fragmenter);for(ScoreDoc scoreDoc:hits.scoreDocs){Document doc=is.doc(scoreDoc.doc);System.out.println(doc.get("city"));System.out.println(doc.get("desc"));String desc=doc.get("desc");if(desc!=null){TokenStream tokenStream=analyzer.tokenStream("desc", new StringReader(desc));System.out.println(highlighter.getBestFragment(tokenStream, desc));}}reader.close();}public static void main(String[] args) {String indexDir="D:\\lucene-exercise\\lucene6";String q="南京文明";try {search(indexDir,q);} catch (Exception e) {e.printStackTrace();}}
}
贴一下运行效果:
好了,博文介绍到这里吧,有需要交流的可以在下面留言,或者加我qq:1948831260进行技术交流
java之全文索引搜索lucene之增删改查文档与中文分词搜索相关推荐
- 商城项目16_es简介、详解倒排索引、安装es以及kibana、检索es基本信息、增删改查文档
文章目录 ①. es - 背景.概述.功能.场景 ②. 核心概念 - 索引.类型.文档.映射 ③. es - 详解倒排索引 ④. 安装elasticSearch.kibana 7.4.2 ⑤. 索引操 ...
- java jdbc 连接mysql数据库 实现增删改查
好久没有写博文了,写个简单的东西热热身,分享给大家. jdbc相信大家都不陌生,只要是个搞java的,最初接触j2ee的时候都是要学习这么个东西的,谁叫程序得和数据库打交道呢!而jdbc就是和数据库打 ...
- java对mysql的简单操作——增删改查的总结
增删改查的详细内容可以点击以下链接: java对mysql的简单操作--增加数据 java对mysql的简单操作--删除数据 java对mysql的简单操作--修改数据 java连接mysql5.1教 ...
- java map 输入 查询 修改_Mybatis增删改查mapper文件写法详解
1. 插入 INSERT sql命令(命令里通过#{}获取对象属性) EG: INSERT INTO PRAC_PERSON(p_NAME,P_PASSWORD) VALUES(#{name},#{p ...
- html单页面js完成表数据库自动生成带注释的java实体类和简单的增删改查sql
支持Mysql和Oracle,mybatis和ibatis可选.功能主要还是字符串的拼凑完成的,把用把表信息复制过来或者增加后台,就可以生成简单的增删改查了 临时体验点这里 我也不知道地址什么时候失效 ...
- java上安装zookeeper并且实现增删改查
目录 一..创建Maven工具 二.将Maven的默认配置文件设置为自己下载的配置文件(非必要) 三.在maven文件中导入zookeeper依赖 四.创建增删改查类MyzkTest 五.实现zook ...
- SharePoint 2013 搜索SharePoint 特定列和特定文档(自己定义搜索)
SharePoint 2013 搜索SharePoint 特定列和特定文档 1,操作步骤和图例,因语言和版本号的不同 我尽量使用抓图方式. 2. In Central Administration, ...
- Java 使用List集合实现图书增删改查
Book.java /*** @Author ꧁ʚVVcatɞ꧂* @Date 2020/6/22 23:47 星期一* @ProjectName Book* @PackageName PACKAGE ...
- 使用Java JdbcTemplate对mySQL进行CRUD增删改查操作
create方法:用字符串拼接构造一个SQL命令:"insert into Student (name, age) values (?, ?)" 然后传入jdbcTemplateO ...
最新文章
- 如何利用 Myflash 解析 binlog ?
- PHP常用工具函数之手机号相关
- ClickHouse【资源分享 01】Linux环境 clickhouse-19.7.3.9 离线安装文件分享(百度云盘)
- SpringBoot底层注解-@ConfigurationProperties配置绑定
- MYSQL中有时候不得不使用replace()去掉特殊字符,写在这里备用一下
- SQL Server 2005 高级程序设计 学习笔记(2)
- Android屏幕禁止休眠的方法
- 南开大学计算机学院夏令营,2022保研夏令营:南开大学计算机学院云端夏令营通知...
- VS2012使用 MSDN教程
- 【原创】破解无线路由密码的那些事儿
- 【解决】 io.lettuce.core.RedisCommandExecutionException: ERR wrong number of arguments for 'set' command
- 2018华东师范软件复试机试
- 博纳影业明日上市:于冬陷入与江疏影绯闻 被曝斥资千万买珠宝
- dwg格式转换成jpg图片
- 朴素和KMP匹配算法(java)
- JVM内存模型和性能调优:阿里巴巴Arthas调优工具:什么是Arthas- 第43篇
- **阿里云ECS Linux服务器图形化界面安装方法 Ubuntu**
- ip-纯真库:批量获取ip归属地
- 计算机械结构变形,机械结构温度变化的位移计算.ppt
- 强大的iOS开发必备工具
热门文章
- 凡事都得有个度,SEO优化过程的七大忌讳...
- githHub使用基础指南
- java 中成员变量的名字和类的方法的名字可以一样.
- 看看OpenHarmony编译出的镜像中都有啥
- 机器学习代码实现:多元线性回归(梯度下降法)吴恩达课后题目
- MEMS 陀螺仪抗震动
- 三星掐住弱点锁喉,台积电危矣
- 定理在数学中的简写形式_这些鲜为人知的数学定理,颠覆你的认知!
- c语言中四个字节八位字长,C语言中显示变量所占字节数;字节、字、字长;原码、反码、补码...
- 为什么Scala这么受欢迎