如何实现全文检索
可以使用Lucene实现全文检索。Lucene是apache下的一个开源代码的全文检索引擎工具包。提供了完整的查询引擎和索引引擎,部分文本分析引擎。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能。
全文检索的应用场景
对于数据量大、数据结构不固定的数据可采用全文检索方式搜索,比如百度、Google等搜索引擎、论坛站内搜索、电商网站站内搜索等。
索引和搜索流程图
1.绿色表示索引过程,对要搜索的原始内容进行索引构建一个索引库,索引过程包括:确定原始内容即要搜索的内容->采集文档->创建文档->分析文档->索引文档
2.红色表示搜索过程,从索引库中搜索内容,搜索过程:用户通过搜索界面->创建查询->执行搜索,从索引库搜索->渲染搜索结果
开发环境
版本:lucene(版本号)
jdk要求:1.7以上
所使用的jar包
lucene-core-(版本号)
lucene-analyrers-common-(版本号)
lucene-queryparser-(版本号)
其他
commons-io-(版本号)
junit-(版本号)
创建索引库
@Test
public void createIndex()throws Exception{
//1.指定索引存放的位置,可以是内存也可以是磁盘。
//索引库保存到内存中,一般不用
//Directory directory = new RAMDirectory();
//保存到磁盘上
Directory directory = FSDirectory.open(new File("G:\\temp\\index"));
//2.创建一个IndexWriter对象,需要一个分析器对象。
Analyzer analyzer = new StandardAnalyzer();
//参数1:lucene的版本号,第二个参数:分析器对象
IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST, analyzer);
//参数1:索引库存放的路径 参数2:配置信息,其中包含分析器对象
IndexWriter indexWriter = new IndexWriter(directory, conf);
//3.获得原始文档,使用Io流读取文本文件
File docPath = new File("E:\\TEST");
for (File f : docPath.listFiles()) {
//取文件名
String fileName = f.getName();
//取文件路径
String filePath = f.getPath();
//文件的内容
String fileContent = FileUtils.readFileToString(f);
//文件的大小
long fileSize = FileUtils.sizeOf(f);
//4.创建文档对象
Document document = new Document();
//创建域
//参数1:域的名称 参数2:域的内容 参数3:是否存储
TextField fileNameField = new TextField("name", fileName, Store.YES);
//参数1:域的名称 参数2:域的内容
StoredField filePathField = new StoredField("path", filePath);
//参数1:域的名称 参数2:域的内容 参数3:是否存储
TextField fileContentField = new TextField("cotent", fileContent, Store.NO);
//参数1:域的名称 参数2:域的内容 参数3:是否存储
LongField fileSizeField =new LongField("size", fileSize, Store.YES);
//5.向文档添加域
document.add(fileNameField);
document.add(filePathField);
document.add(fileContentField);
document.add(fileSizeField);
//6.把文档对象写入索引库
indexWriter.addDocument(document);
}
//7.关闭IndexWriter对象
indexWriter.close();
}
查询索引库
@Test
public void searchIndex()throws Exception{
//1.指定索引库存放位置
Directory directory = FSDirectory.open(new File("G:\\temp\\index"));
//2.使用IndexReader对象打开索引库
IndexReader indexReader = DirectoryReader.open(directory);
//3.创建一个IndexSerarcher对象,构造方法需要一个indexReader对象
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
//4.创建一个查询对象,需要指定查询域及要查询的关键字
//term的参数1:要搜索的域 参数2:搜索的关键字
Query query = new TermQuery(new Term("name","apache"));
//参数1:查询条件 参数2:查询结果返回的最大值
//5.取查询结果
TopDocs topDocs = indexSearcher.search(query, 10);
//取查询结果总记录数
System.out.println("查询结果总记录数:"+ topDocs.totalHits);
//6.遍历查询结果并打印
for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
//取文档id
int id = scoreDoc.doc;
//从索引库中取文档对象
Document document = indexSearcher.doc(id);
//取属性
System.out.println(document.get("name"));
System.out.println(document.get("size"));
System.out.println(document.get("content"));
System.out.println(document.get("path"));
}
//7.关闭IndexReader对象
indexReader.close();
}
分析器的分词效果
@Test
public void testAnanlyzer() throws Exception{
//创建一个分析器对象
Analyzer analyzer = new StandardAnalyzer();
//从分析器对象中获取tokenStream对象
//参数1:域的名称,可以为空或者""
//参数2:要分析的文本内容
TokenStream tokenStream = analyzer.tokenStream("", "The Spring Framework provides a comprehensive programming and configuration model.");
//设置一个引用,引用可以多重类型,可以时候关键词的引用、偏移量的引用
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
//偏移量
OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
//调用tokenStream的reset方法
tokenStream.reset();
//使用while循环变量单词列表
while (tokenStream.incrementToken()){
System.out.println("star->"+offsetAttribute.startOffset());
//打印单词
System.out.println(charTermAttribute);
System.out.println("end->"+offsetAttribute.startOffset());
}
//关闭tokenStream
tokenStream.close();
}
IK分词器
jar包
配置文件
//查看分析器的分词效果
@Test
public void testAnanlyzer() throws Exception{
//创建一个分析器对象
Analyzer analyzer = new IKAnalyzer();
//从分析器对象中获取tokenStream对象
//参数1:域的名称,可以为空或者""
//参数2:要分析的文本内容
TokenStream tokenStream = analyzer.tokenStream("", "白富美二货数据库中存储的数据是高富帅结构化数据,即行数据java,可以用二维表结构来逻辑表达实现的数据.");
//设置一个引用,引用可以多重类型,可以时候关键词的引用、偏移量的引用
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
//偏移量
OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
//调用tokenStream的reset方法
tokenStream.reset();
//使用while循环变量单词列表
while (tokenStream.incrementToken()){
System.out.println("star->"+offsetAttribute.startOffset());
//打印单词
System.out.println(charTermAttribute);
System.out.println("end->"+offsetAttribute.startOffset());
}
//关闭tokenStream
tokenStream.close();
}
分析器使用场景
1.创建索引时
2.查询索引时
维护索引库-添加文档
@Test
public void addDocument() throws Exception{
Directory directory = FSDirectory.open(new File("G:\\temp\\index"));
Analyzer analyzer = new IKAnalyzer();
//参数1:Iucene的版本号,第二个参数:分析器对象
IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST, analyzer);
IndexWriter indexWriter = new IndexWriter(directory,conf);
//创建Document对象
Document document = new Document();
//创建域
TextField FileNameField = new TextField("name", "测试文件.txt", Store.YES);
StoredField FilepathFile = new StoredField("path", "G:\\temp\\测试文件.txt");
document.add(FileNameField);
document.add(FileNameField);
//写入索引库
indexWriter.addDocument(document);
//关闭资源
indexWriter.close();
}
维护索引库-删除文档
//删除全部文档
public void deleteAllDocument()throws Exception{
//获得IndexWriter对象
IndexWriter indexWriter = this.getIndexWriter();
//调用删除方法删除索引库
indexWriter.deleteAll();
indexWriter.close();
}
维护索引库-根据查询删除文档
public void deleteDocmenttByQuery()throws Exception{
IndexWriter indexWriter =this.getIndexWriter();
//指定查询条件
Query query = new TermQuery(new Term("name","apahce"));
//删除文档
indexWriter.deleteDocuments(query);
//关闭资源
indexWriter.close();
}
维护索引库-更新文档
//更新索引库
public void updateDocument()throws Exception{
IndexWriter indexWriter = this.getIndexWriter();
//创建一个新的文档对象
Document document =new Document();
document.add(new TextField("name","更新后的文档",Store.YES));
document.add(new TextField("content", "更新后的文档内容",Store.YES));
//term对象:指定要删除域及要删除的关键词,先根据term查询,把查询结果删除,然后追加一个新的文档
indexWriter.updateDocument(new Term("name","spring"),document);
//关闭资源
indexWriter.close();
}