创建索引
获得文档 原始文档:要基于那些数据来进行搜索,那么这些数据就是原始文档。 搜索引擎:使用爬虫获得原始文档 站内搜索:数据库中的数据。 本地搜索:直接使用io流读取磁盘上的文件。 * 分析文档(每个文档拆分成不同的域,再把每个域进行分词) 构建Trem对象 每个关键词都封装成一个Term对象中(Term中包含两部分内容:关键词所在的域(字段名)、关键词本身(字段值) 把Trem根据空格进行字符串分词,得到一个单词列表,把单词统一转换成小写,去除标点符号,去除停用词 构建Document对象 对应每个原始文档创建一个Document对象 每个document对象中包含多个Trem(即上一步要进行索引或者保存的Trem) 创建索引 基于关键词列表创建一个索引,保存到索引库中 索引库中:索引、document对象、关键词和文档的对应关系 通过词语找文档,这种索引的结构叫倒排索引结构。查询索引
用户查询接口 用户输入查询条件的地方(例如:百度的搜索框) 把关键词封装成一个查询对象 要查询的域、要搜索的关键词 执行查询 根据要查询的关键词到对应的域上进行搜索。 找到关键词,根据关键词找到对应的文档 渲染结果 根据文档的id找到文档对象 对关键词进行高亮显示、分页处理,最终展示给用户看。注意:
Lucene保存的数据没有结构,只是会根据能够索引的Term建立索引树,然后每次查询索引树找到对应的Document(每个文档都有一个唯一的编号,就是文档id) 要保存结构化数据还是关系型数据库 环境准备依赖
org.apache.lucene
lucene-core
7.4.0
org.apache.lucene
lucene-queryparser
7.4.0
org.apache.lucene
lucene-analyzers-common
7.4.0
org.apache.commons
commons-io
1.3.2
IK分词器(中文分词器)
链接:https://pan.baidu.com/s/1Rsled6iBdgOZAbjzxS_BCA
提取码:f5wh
复制这段内容后打开百度网盘手机App,操作更方便哦
IKAnalyzer.cfg.xml 必须在classpath 一级路径下,而hotword.dic(热词)、stopword.dic(禁用词)是由IKAnalyzer.cfg.xml 指定路径
步骤
创建一个Directory对象,指定索引库保存的位置。 基于Directory对象创建一个IndexWriter对象 读取磁盘上的文件,对应每个文件创建一个文档对象。 向文档对象中添加域 把文档对象写入索引库 关闭indexwriter对象public void addDocument() throws Exception {
/**
* 1、创建一个Director对象,指定索引库保存的位置。
* 把索引库保存在内存中:Directory directory = new RAMDirectory();
* 把索引库保存在磁盘:
*/
Directory directory = FSDirectory.open(new File("C:\\temp\\index").toPath());
/**
* 2、基于Directory对象创建一个IndexWriter对象
* IndexWriterConfig config=new IndexWriterConfig() //不指定为IKAnalyzer会默认使用自带的英文分词器
*/
IndexWriterConfig config = new IndexWriterConfig(new IKAnalyzer());
IndexWriter indexWriter = new IndexWriter(directory, config);
/**
* 3、读取磁盘上的文件,对应每个文件创建一个文档对象。
*/
File dir = new File("C:\\temp\\searchsource");
File[] files = dir.listFiles();
for (File f : files) {
//取文件名
String fileName = f.getName();
//文件的路径
String filePath = f.getPath();
//文件的内容
String fileContent = FileUtils.readFileToString(f, "utf-8");
//文件的大小
long fileSize = FileUtils.sizeOf(f);
/**
* 4、创建Field
* 参数1:域的名称,参数2:域的内容,参数3:是否存储
*/
Field fieldName = new TextField("name", fileName, Field.Store.YES);
Field fieldPath = new StoredField("path", filePath);
Field fieldContent = new TextField("content", fileContent, Field.Store.YES);
Field fieldSizeValue = new LongPoint("size", fileSize);
//创建文档对象
Document document = new Document();
//向文档对象中添加域
document.add(fieldName);
document.add(fieldPath);
document.add(fieldContent);
document.add(fieldSizeValue);
/**
* 5、把文档对象写入索引库
*/
indexWriter.addDocument(document);
}
/**
* 6、关闭indexwriter对象
*/
indexWriter.close();
}
常用Filed类型
Stored 属性说明
如果有的字段要在索引库只做索引(即只在搜索的时候使用),而不用在搜到对应Document的时候获取这个字段的值(即documet.get() 取不到值)Indexed 属性说明
这个字段是否做查询时的索引(比如:url、path等就不用做索引,所以应该用StroedFiled)Analyzed 属性说明
这个字段表明是否分词,因为有的句子不可拆分(比如身份证号)分词器说明
测试分词 public void testTokenStream() throws Exception {
//1)创建一个Analyzer对象,StandardAnalyzer对象
// Analyzer analyzer = new StandardAnalyzer(); //自带的英文分词器
Analyzer analyzer = new IKAnalyzer();
//2)使用分析器对象的tokenStream方法获得一个TokenStream对象
//第一个参数指定分词字段(没有document使用的话不用指定)
//第二个参数是分词的句子
TokenStream tokenStream = analyzer.tokenStream("", "Lucene是一款高性能的、可扩展的信息检索(IR)工具库。信息检索是指文档搜索、文档内信息搜索或者文档相关的元数据搜索等操作。");
//3)向TokenStream对象中设置一个每个词类型引用,相当于数一个指针
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
//4)调用TokenStream对象的rest方法。如果不调用抛异常
tokenStream.reset();
//5)使用while循环遍历TokenStream对象
while(tokenStream.incrementToken()) {
System.out.println(charTermAttribute.toString());
}
//6)关闭TokenStream对象
tokenStream.close();
}
修改热词或者禁用词
增加热词(在分词时把该词当一个整体):hotword.dic 增加禁用词(把句子分词后会删除该词):stopword.dic注意
hotword.dic和ext_stopword.dic文件的格式为UTF-8,注意是无BOM 的UTF-8 编码。
也就是说禁止使用windows记事本编辑扩展词典文件
使用EditPlus.exe保存为无BOM 的UTF-8 编码格式,如下:
删除索引库 删除整个索引库 public void deleteAllDocument() throws Exception {
//创建一个IndexWriter对象,使用IKAnalyzer作为分析器
IndexWriter indexWriter = new IndexWriter(
FSDirectory.open(new File("C:\\temp\\index").toPath()),
new IndexWriterConfig(new IKAnalyzer()));
//删除全部文档
indexWriter.deleteAll();
//关闭索引库
indexWriter.close();
}
把查询到的删除
public void deleteDocumentByQuery() throws Exception {
//创建一个IndexWriter对象,使用IKAnalyzer作为分析器
IndexWriter indexWriter = new IndexWriter(
FSDirectory.open(new File("C:\\temp\\index").toPath()),
new IndexWriterConfig(new IKAnalyzer()));
indexWriter.deleteDocuments(new Term("name", "apache"));
indexWriter.close();
}
更新索引库
public void updateDocument() throws Exception {
//创建一个IndexWriter对象,使用IKAnalyzer作为分析器
IndexWriter indexWriter = new IndexWriter(
FSDirectory.open(new File("C:\\temp\\index").toPath()),
new IndexWriterConfig(new IKAnalyzer()));
//创建一个新的文档对象
Document document = new Document();
//向文档对象中添加域
document.add(new TextField("name", document.get("name"), Field.Store.YES));
document.add(new TextField("name1", "新增字段name2", Field.Store.YES));
//更新操作
indexWriter.updateDocument(new Term("name", "spring"), document);
//关闭索引库
indexWriter.close();
}
说明
Lucene的查找是先删除查找到的Document,然后再增加 Lucene的Document 没有结构,所以可以增加任意Trem(字段),同样查找时也是通过某个Trem找到整个Document