数据库中保存的数据,磁盘中保存的数据都可以算做数据,常用的数据分为两种,一种是结构化数据,数据格式固定,长度有限,例如数据库中存储的数据,另一种是非结构化数据,数据格式不固定,长度不固定,例如磁盘中存储的文档数据。
结构化数据的查询可以使用sql查询,查询起来方便。
而非结构化数据的查询就要使用本章中描述的技术,全文检索技术--Lucene,它可以将非结构化数据编程结构化数据,当数据量比较小时,比如一个内容较少的文档,可以适当的使用io流进行读取,完成匹配,对字符串的常规操作,但是当文档内容较大时,需要将文档内容进行合理的拆分,根据得到的词汇列表创建索引,这种先创建索引,然后查询索引的过程就是全文检索。
全文检索的应用领域:对于数据量大,数据机构不固定的数据可以使用全文检索方式进行搜索,例如百度,google等搜索引擎。
索引和搜索流程图:
Lucene的有点就是一次创建索引,多次查询使用
使用Lucene实现全文检索的流程步骤:
1,获取原始文档
2,创建文档对象,为每个原始文档创建一个对应的Document对象,文档中包含若干个域filed,每个文档中包含多个域,不同的document可以包含不同的域,通一个document中可以包含相同的域,每个文档对应一个唯一的id
3,分析文档,分析文档中的内容,分析相关域的内容,
(1)根据控件进行分词,(2)删除标点符号,(3)去除停用词(没有意义的词)(4)将单词统一转换为小写,(5)最终得到一个关键词列表
4,创建索引,
(1)基于分析分档后获得到的关键词列表创建索引(2)把单词和文档的对应关系保存
索引库中包含两部分,一是索引,二是文档对象,索引库维护了索引与文档对象之间的关系,如下:
5,查询索引
(1)创建查询对象,根据查询条件创建一个查询对象Query,Lucene根据query对象查询索引库
(2)执行查询,查询获得一个document文档对象的id列表,根据document对象的id获取文档中的内容
(3)渲染结果,对查询后的结果进行高亮显示,分页显示等等操作
入门程序
1,创建索引库步骤:
第一步:创建一个java工程。
第二步:导入jar包。lucene-core-4.10.3.jar、lucene-analyzers-common-4.10.3.jar、commons-io-2.4.jar
第三步:创建一个Directory对象,指定索引库存放的位置。可以放到内存中也可以放到磁盘上。一般都是保存到磁盘上。
第四步:创建一个IndexWriter对象。需要指定两个参数,一个Directory对象一个是分析器对象。
第五步:循环读取磁盘中XXX/XX目录下的文档。
第六步:创建一个Document对象。
第七步:向Document对象中添加域。
域有三个属性:是否分析、是否索引、是否存储。
是否分析:取决于是否对域的内容进行分词。
是否索引:取决于是否在域上进行搜索。
是否存储:取决于是否展示个用户看。
常用的Field类型:
第八步:把文档对象写入索引库。使用IndexWriter对象。
第九步:关闭IndexWriter对象。
,2,查询索引库步骤:
第一步:创建一个Directory对象。指定索引库存放的目录
第二步:创建一个IndexReader对象。打开索引库
第三步:创建一个IndexSearcher对象,构造方法中需要IndexReader对象。
第四步:创建一个Query对象。两个参数:要搜索的域及要搜索的关键词。
第五步:IndexSearcher执行查询。
第六步:得到一个文档id列表。
第七步:根据id取文档对象。
第八步:从文档对象中取域的内容,展示给用户。
第九步:关闭IndexReader。
package lucene_demo;
import java.io.File;
import org.apache.commons.io.FileUtils;
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.Field.Store;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
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.apache.lucene.util.Version;
public class FirstIndexDemo {
public static void main(String[] args) {
try {
/*testCreateIndex();
System.out.println("创建索引完毕!!!");*/
testSearchIndex();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 测试创建索引的方法
* @throws Exception
*/
public static void testCreateIndex() throws Exception{
//创建一个Directory对象,指定索引库存放的位置。可以放到内存中也可以放到磁盘上。一般都是保存到磁盘上。
//放到内存中
//Directory directory = new RAMDirectory();
//放到磁盘上
Directory directory = FSDirectory.open(new File("E:\\lucene"));
//创建一个IndexWriter对象。需要指定两个参数,一个Directory对象一个是分析器对象。
Analyzer analyzer = new StandardAnalyzer();
//第一个参数Lucene对应的版本号
//第二个参数分析器对象
IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, analyzer);
IndexWriter indexWriter = new IndexWriter(directory,config);
//循环读取D:/传智播客/01.课程/04.lucene/01.参考资料/searchsource目录下的文档。
File dir = new File("E:\\pachong\\text");
for(File f :dir.listFiles()){
//取文件名
String fileName = f.getName();
//文件路径
String filePath = f.getAbsolutePath();
//文件内容
String fileContent = FileUtils.readFileToString(f);
//文件大小
long fileSize = FileUtils.sizeOf(f);
//创建一个Document对象。
Document document = new Document();
//第一个参数:域的名称
//第二个参数:域的内容
//第三个参数:是否存储
Field fileNameField = new TextField("title",fileName,Store.YES);
Field fileContentField = new TextField("content",fileContent,Store.NO);
Field filePathField = new StoredField("path",filePath);
Field fileSizeField = new LongField("size",fileSize,Store.YES);
//向Document对象中添加域。
document.add(fileNameField);
document.add(fileContentField);
document.add(filePathField);
document.add(fileSizeField);
//把文档写入索引库
indexWriter.addDocument(document);
}
//关闭IndexWriter对象
indexWriter.close();
}
/**
* 测试查询索引库的方法
* @throws Exception
*/
public static void testSearchIndex() throws Exception{
//创建一个Directory对象。指定索引库存放的目录
Directory directory = FSDirectory.open(new File("E:\\lucene"));
//创建一个IndexReader对象。打开索引库
IndexReader indexReader = DirectoryReader.open(directory);
//创建一个IndexSearcher对象,构造方法中需要IndexReader对象。
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
//创建一个Query对象。两个参数:要搜索的域及要搜索的关键词。
Query query = new TermQuery(new Term("content","个"));
//IndexSearcher执行查询。
//第一个参数查询对象,第二个参数返回结果的记录数
TopDocs topDocs = indexSearcher.search(query, 10);
//取查询结果的总记录数
System.out.println("查询记录的总记录数:"+topDocs.totalHits);
//得到一个文档id列表。
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
//根据id取文档对象。
for (ScoreDoc scoreDoc : scoreDocs) {
//文档对应的id
int id = scoreDoc.doc;
//根据id取Document对象
Document document = indexSearcher.doc(id);
//从文档对象中取域的内容,展示给用户。
System.out.println(document.get("title"));
System.out.println(document.get("content"));
System.out.println(document.get("size"));
System.out.println(document.get("path"));
System.out.println("----------------------------");
}
//关闭IndexReader。
indexReader.close();
}
}