1.全文检索
顺序扫描 , 遍历文档查询内容
倒排索引 , 通过内容去查文档
2.lucene原理
内容要与文档建立关系
创建索引
假设有一个三国演义.txt文档 ,希望通过搜索三国关键字将这个文档搜索出来 , 首先要针对这个标题分词 , 将他切分成"三国",“演义"等大家习惯搜索关键词 , 这就是trem(关键词) , 每个term都要创建索引 , 加快搜索 . 索引有了 , 还需要明确与文档建立关系 , 但是这个关系太大了 , 需要再细化一层 , 也就是域(field) , 域可以理解成一个文档不同的属性 , 针对三国演义这个文档 , 他可以有文档名称 , 文档路径 , 文档大小 , 内容 , hash值等属性 , 每个域是一个kv结构 , v记录了属性值 , 例如 “三国演义.txt” ,“c:/小说/三国演义.txt”,“东汉末年…” , 然后根据每个域都要去进行分词 , 拆分出关键词term , 每个term都要记录自己对应的域(field) ,这样大家在查询"三国”,"c:/小说"关键字时 , 搜索结果中将匹配出三国演义.text . 最后将这些域 , term 集合起来就构成了lucene中的概念 : document , 一个document就对应一个原始文档 , 每个document都有自己的唯一标识id , 一个term会记录自己关联的document 的id
创建索引是一个漫长的过程 , 一旦创建 , 可以加快以后的所有查询操作 , 好比大家宁愿将一些初始化工作放到服务启动时 , 虽然加长了服务启动的时间 , 但是服务运行时压力将减小 , 更有效率的提供服务 .
创建索引最终生成索引库 , 索引库中有文档 , 文档中有域 , 域中有域的名称与值 , 类似k,v .
分词器 , 一般使用ik分词器 , 分词器会根据导入的词库和停词 , 对域的内容进行分词 , 比如 “我是中国人” , 会被分成‘我’ ‘是’ ‘我是’ ‘中国人’ ‘中国’ 等。。
field域有不同的属性,对于域中的内容可以进行存储,也可以进行分析
Field是lucene用来描述域的父类
比如像身份证号订单号之类具有含义的数字,就不应该进行分词,在储存的时候使用Field类的子类StringField,就可以仅对该值进行存储,添加索引,但不进行分词分析
3.lucene api测试
lucene中的对于文档也存在增删改查 , 其中更新原理为删除旧的 , 添加新的
引入依赖
<dependencies>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>6.6.1</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>6.6.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
import org.apache.commons.io.FileUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
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.queryparser.classic.ParseException;
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.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.junit.After;
import org.junit.Before;
import org.wltea.analyzer.lucene.IKAnalyzer;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
public class Test {
IndexReader indexReader;
IndexSearcher indexSearcher;
//创建索引库
public static void main(String[] args) throws Exception {
Directory d = FSDirectory.open(Paths.get("D:\\lesson\\lucene\\indexRepository"));
//写入索引库的配置,指定一个分词器,默认使用标准分词器。
IndexWriterConfig conf = new IndexWriterConfig(new IKAnalyzer());
//创建第三方分词器对象
//创建一个写入索引库的对象
IndexWriter indexWriter = new IndexWriter(d, conf);
//得到数据源所在文件夹
File sourceFile = new File("D:\\lesson\\lucene\\souce");
//得到数据源中所有文件的集合
File[] files = sourceFile.listFiles();
for (File file : files) {
//文件标题
String fileName = file.getName();
//文件内容
String fileContent = FileUtils.readFileToString(file);
//文件路径
String filePath = file.getPath();
//文件大小
Long fileSize = FileUtils.sizeOf(file);
//把上面四个字段转成域
Field nameField = new TextField("fileName", fileName, Field.Store.YES);
Field contentField = new TextField("fileContent", fileContent, Field.Store.YES);
Field pathField = new StoredField("filePath", filePath);
Field sizeField = new StoredField("fileSize", fileSize);
//创建一个文档
Document document = new Document();
document.add(nameField);
document.add(contentField);
document.add(pathField);
document.add(sizeField);
//写入所依靠
indexWriter.addDocument(document);
}
//关闭资源
indexWriter.close();
}
//删除索引库
@org.junit.Test
public void delIndex() throws IOException {
//指定一个索引库并直接打开
Directory d = FSDirectory.open(Paths.get("D:\\lesson\\lucene\\indexRepository"));
//写入索引库的配置,指定一个分词器,默认使用标准分词器。
IndexWriterConfig conf = new IndexWriterConfig(new StandardAnalyzer());
//创建一个写入索引库的对象
IndexWriter indexWriter = new IndexWriter(d, conf);
//删除索引库中的数据
indexWriter.deleteAll();
//关闭资源或提交事务
indexWriter.close();
}
//测试ik分词器
@org.junit.Test
public void ikTest() throws IOException {
//创建一个标准分析器对象
Analyzer analyzer = new IKAnalyzer();
//获取tokenStream对象
//参数1域名 2要分析的文本内容
TokenStream tokenStream = analyzer.tokenStream("", "test a lucene 程序,杯莫停");
//添加引用,用于获取每个关键词
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
//添加一个偏移量的引用,记录了关键词的开始位置以及结束位置
OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
//将指针调整到列表的头部
tokenStream.reset();
//遍历关键词列表,incrementToken判断是否结束
while (tokenStream.incrementToken()) {
System.out.println("开始--->" + offsetAttribute.startOffset());
System.out.println(charTermAttribute);
System.out.println("结束--->" + offsetAttribute.endOffset());
}
tokenStream.close();
}
//测试用例 初始化
@Before
public void init() throws IOException {
Directory d = FSDirectory.open(Paths.get("D:\\lesson\\lucene\\indexRepository"));
//获取索引流对象
indexReader = DirectoryReader.open(d);
//创建索引流查询对象
indexSearcher = new IndexSearcher(indexReader);
}
//query查询
@org.junit.Test
public void queryParse() throws IOException, ParseException {
//创建一个标准分析器对象
Analyzer analyzer = new IKAnalyzer();
QueryParser queryParser = new QueryParser("fileName",analyzer);
Query query = queryParser.parse("456");
printResult(query);
}
//根绝query对象进行查询
public void printResult(Query query) throws IOException {
TopDocs topDocs = indexSearcher.search(query, 10);
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
System.out.println("总命中数:"+topDocs.totalHits);
//遍历文档集
for (ScoreDoc scoreDoc : scoreDocs) {
//获取文档id
int docId = scoreDoc.doc;
//根据id查询出文档
Document doc = indexSearcher.doc(docId);
//
System.out.println("文档内容:"+doc.get("fileContent"));
System.out.println("文档名称:"+doc.get("fileName"));
System.out.println("文档路径:"+doc.get("filePath"));
System.out.println("文档大小:"+doc.get("fileSize"));
}
indexReader.close();
}
推荐一篇详细文档 :
`https://blog.csdn.net/liuhaiabc/article/details/52346493