Lucene

为什么使用Lucene(全文检索)

应用场景:搜索引擎(全文检索)

站内搜索:淘宝站内商品的搜索,博客园找找看 等

基本概念

什么是全文检索

全文检索是计算机程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置。当用户查询时根据建立的索引查找,类似于通过字典的检索字表查字的过程

建立索引的过程:全文检索是计算机程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置

查询过程:当用户查询时根据建立的索引查找,类似于通过字典的检索字表查字的过程

全文检索(Full-Text Retrieval)以文本作为检索对象,找出含有指定词汇的文本。全面、准确和快速是衡量全文检索系统的关键指标。

全文检索的特点

  1. 只处理文本数据

  2. 不处理语义,数据的匹配,不做语义分析

  3. 搜索时英文不区分大小写

  4. 结果列表有相关度排序

    相关度分数:搜索关键词和结果数据 匹配程度 Lucene自动计算 可以人为修改

全文检索和模糊匹配的区别

模糊匹配的缺点

  1. 数据不够准备 模糊匹配要求 搜索关键词的每一个字以及顺序 都需要和数据库中的数据 一一对应 才能够找结果

    需求:因为用户输入的关键词 千奇百怪 不可能做到和数据库的原始数据 一一对应 所以通过模糊匹配很难的到结果

  2. 几乎不能使用上索引

    除了右模糊 都使用不了索引【执行计划是确定一条sql能不能使用索引的标准】

全文检索的优点

  1. 搜索结果更加准确 全面

  2. 效率更高

    文检索的速度大大快于SQL的like搜索的速度。这是因为查询方式不同造成的,以查字典举例:数据库的like就是一页一页的翻,一行一行的找,而全文检索是先查目录,得到结果所在的页码,再直接翻到这一页

  3. 相关度排序

    查出的结果没有相关度排序,不知道我想要的结果在哪一页。我们在使用百度搜索时,一般不需要翻页,为什么?因为百度做了相关度排序:为每一条结果打一个分数,这条结果越符合搜索条件,得分就越高,叫做相关度得分,结果列表会按照这个分数由高到低排列,所以第1页的结果就是我们最想要的结果

基本使用

导入依赖

<!--核心依赖-->
<dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-core</artifactId><version>4.4.0</version>
</dependency>
<!--分词器 对文本做分词处理-->
<dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-analyzers-common</artifactId><version>4.4.0</version>
</dependency>
<!--智能分词器-->
<dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-analyzers-smartcn</artifactId><version>4.4.0</version>
</dependency>
<!--查询-->
<dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-queryparser</artifactId><version>4.4.0</version>
</dependency>

索引的创建

/*** 创建索引*/
@Test
public void test1() throws IOException {Integer id = 1;String title = "背影";String author = "朱自清";String content = "你站在这里不要动,我去给你买几个橘子";/*** 1.准备文章数据  将数据封装在Document对象 文档对象* Document add方法封装数据  参数为Field对象* 八种基本类型和StringField 暂时可以认为不分词* TextField 文本Field 会做分词处理 需要被查询的数据 要定义为文本Field* Field*  参数1  属性名*  参数2  属性值*  参数3  Field.Store.YES 固定写法*/Document document = new Document();document.add(new IntField("id",id, Field.Store.YES));document.add(new TextField("title",title, Field.Store.YES));document.add(new TextField("author",author, Field.Store.YES));document.add(new TextField("content",content, Field.Store.YES));/*** 2.通过程序扫描文章数据创建索引* IndexWriter 索引写出对象(相当于一个流) 把文档对象写出到索引库 在写出的过程中会自动做分词处理 并且 创建索引* IndexWriter 对象* 参数1 定义索引库的位置  FSDirectory directory = FSDirectory.open(new File("E://lucene"));* 参数2 定义索引创建的配置 索引配置对象* IndexWriterConfig* 参数1 当前Lucene的版本号* 参数2 分词器对象 分词器:对文本做分词处理    StandardAnalyzer 标准分词器   StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_44);*/FSDirectory directory = FSDirectory.open(new File("E://lucene"));StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_44);IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_44,analyzer);IndexWriter indexWriter = new IndexWriter(directory,config);/*** 将文章数据 给 索引写出对象*/indexWriter.addDocument(document);/*** 将文章数据提交到索引库  会自动做分词处理 并且 创建索引*/indexWriter.commit();/*** 释放资源*/indexWriter.close();
}

通过搜索关键词查询

@Test
public void test2() throws ParseException, IOException {/*** 1.准备搜索关键词*/String keywords = "朱自清的文章";/*** 2.处理搜索关键词* MultiFieldQueryParser 多列属性查询处理的对象* 参数1 Lucene的版本号* 参数2 属性名的数组* 参数3 分词器对象  需要保证和创建索引时候用的一个分词器* parse() 处理关键词 得到一个Query对象*/String[] fields = {"title","author","content"};StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_44);MultiFieldQueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_44,fields,analyzer);Query query = queryParser.parse(keywords);/*** 3.通过处理好的关键词 去 索引库中查询 得到索引(索引词+最终数据的位置信息id)*/DirectoryReader reader = DirectoryReader.open(FSDirectory.open(new File("E://lucene")));IndexSearcher searcher = new IndexSearcher(reader);/*** search 方法* 参数1 Query 对象* 参数2 期望的结果条数** TopDocs 结果集 包含了结果的数据(索引)*/TopDocs topDocs = searcher.search(query, 10);/*** 处理结果集* scoreDocs 包含有分数 和 文档对象的id(原始数据)(位置信息)*/ScoreDoc[] scoreDocs = topDocs.scoreDocs;/*** 4.通过位置信息 得到数据*/for (ScoreDoc scoreDoc : scoreDocs) {System.out.println(scoreDoc.score);/*** docId 文档对象在索引库中的位置信息*/int docId = scoreDoc.doc;/*** 通过位置信息 得到数据 Document*/Document document = searcher.doc(docId);String id = document.get("id");System.out.println(id);String title = document.get("title");System.out.println(title);String author = document.get("author");System.out.println(author);String content = document.get("content");System.out.println(content);}
}

删除索引库

第一天作业

  1. 练习demo 【两遍】

  2. 实现我给的接口

作业讲解

 /*** 将所有文章数据添加至索引库*/@Testpublic void test4() throws IOException {//        文章数据List<CmfzArticle> cmfzArticles = cmfzArticleDao.selectList(null);/*** 1.封装数据 到文档对象中 List<Document>*/List<Document> documents = new ArrayList<>();for (CmfzArticle cmfzArticle : cmfzArticles) {Document document = new Document();document.add(new IntField("articleId",cmfzArticle.getArticleId(), Field.Store.YES));/*** StringField 不分词* TextField 会分词处理 需要被查询的数据 要定义为文本Field*/document.add(new TextField("articleName",cmfzArticle.getArticleName(), Field.Store.YES));document.add(new TextField("articleContent",cmfzArticle.getArticleContent(), Field.Store.YES));/*** 时间 可以 long 类型  String*/document.add(new LongField("articleDate",cmfzArticle.getArticleDate().getTime(), Field.Store.YES));String s = DateTools.dateToString(cmfzArticle.getArticleDate(), DateTools.Resolution.DAY);System.out.println(s);documents.add(document);}/*** 2.通过索引写出对象 写出到索引库*/FSDirectory directory = FSDirectory.open(new File("E://lucene"));IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_44,new StandardAnalyzer(Version.LUCENE_44));IndexWriter indexWriter = new IndexWriter(directory,config);indexWriter.addDocuments(documents);indexWriter.commit();indexWriter.close();}/*** 查询上师文章*/@Testpublic void test5() throws ParseException, IOException {/*** 1.准备搜索关键词*/String keyWords = "曾经有一位上师";/*** 2.处理关键词*/String[] ss = {"articleName","articleContent"};MultiFieldQueryParser parser = new MultiFieldQueryParser(Version.LUCENE_44,ss,new StandardAnalyzer(Version.LUCENE_44));Query query = parser.parse(keyWords);/*** 3.查询*/DirectoryReader reader = DirectoryReader.open(FSDirectory.open(new File("E://lucene")));IndexSearcher indexSearcher = new IndexSearcher(reader);TopDocs topDocs = indexSearcher.search(query, 10);/*** 4.处理结果集*/ScoreDoc[] scoreDocs = topDocs.scoreDocs;for (ScoreDoc scoreDoc : scoreDocs) {int docId = scoreDoc.doc;/*** 通过id 查询数据*/Document document = indexSearcher.doc(docId);String articleId = document.get("articleId");String articleName = document.get("articleName");String articleContent = document.get("articleContent");String articleDate = document.get("articleDate");CmfzArticle cmfzArticle = new CmfzArticle();cmfzArticle.setArticleId(Integer.parseInt(articleId));cmfzArticle.setArticleName(articleName);cmfzArticle.setArticleContent(articleContent);
//            Long类型转时间long l = Long.parseLong(articleDate);Date date = new Date(l);cmfzArticle.setArticleDate(date);
//            日期转StringString s = DateTools.dateToString(date, DateTools.Resolution.DAY);System.out.println(s);System.out.println(cmfzArticle);}}

索引库的基本结构

封装工具类

package com.baizhi.util;import com.baizhi.entity.CmfzArticle;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.*;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;public class LuceneUtil {private static FSDirectory directory = null;private static Analyzer analyzer = null;/*** 做成员变量的初始化*/static {try {directory = FSDirectory.open(new File("E://lucene"));analyzer = new StandardAnalyzer(Version.LUCENE_44);} catch (IOException e) {e.printStackTrace();}}/*** 获取 IndexWriter* @return*/public static IndexWriter getIndexWriter(){IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_44,analyzer);IndexWriter indexWriter = null;try {indexWriter = new IndexWriter(directory,config);} catch (IOException e) {e.printStackTrace();}return indexWriter;}/*** 文章对象 转换 文档对象*/public static List<Document> cmfzArticleToDocument(List<CmfzArticle> cmfzArticles){List<Document> documents = new ArrayList<>();for (CmfzArticle cmfzArticle : cmfzArticles) {Document document = new Document();document.add(new IntField("articleId",cmfzArticle.getArticleId(), Field.Store.YES));/*** StringField 不分词* TextField 会分词处理 需要被查询的数据 要定义为文本Field*/document.add(new TextField("articleName",cmfzArticle.getArticleName(), Field.Store.YES));document.add(new TextField("articleContent",cmfzArticle.getArticleContent(), Field.Store.YES));/*** 时间 可以 long 类型  String*/document.add(new LongField("articleDate",cmfzArticle.getArticleDate().getTime(), Field.Store.YES));documents.add(document);}return documents;}/*** 处理关键词* @param keyWords* @return*/public static Query parsekeyWords(String keyWords){String[] ss = {"articleName","articleContent"};MultiFieldQueryParser parser = new MultiFieldQueryParser(Version.LUCENE_44,ss,analyzer);Query query = null;try {query = parser.parse(keyWords);} catch (ParseException e) {e.printStackTrace();}return query;}/*** 获取IndexSearcher*/public static IndexSearcher getIndexSearcher(){DirectoryReader reader = null;try {reader = DirectoryReader.open(directory);} catch (IOException e) {e.printStackTrace();}return new IndexSearcher(reader);}/*** 处理结果集  得到文章对象集合*/public static List<CmfzArticle> scoreDocToCmfzArticle(ScoreDoc[] scoreDocs,IndexSearcher indexSearcher){List<CmfzArticle> cmfzArticles = new ArrayList<>();for (ScoreDoc scoreDoc : scoreDocs) {int docId = scoreDoc.doc;/*** 通过id 查询数据*/Document document = null;try {document = indexSearcher.doc(docId);} catch (IOException e) {e.printStackTrace();}
//            获取数据String articleId = document.get("articleId");String articleName = document.get("articleName");String articleContent = document.get("articleContent");String articleDate = document.get("articleDate");//            封装对象CmfzArticle cmfzArticle = new CmfzArticle();cmfzArticle.setArticleId(Integer.parseInt(articleId));cmfzArticle.setArticleName(articleName);cmfzArticle.setArticleContent(articleContent);
//            Long类型转时间long l = Long.parseLong(articleDate);Date date = new Date(l);cmfzArticle.setArticleDate(date);//            封装集合cmfzArticles.add(cmfzArticle);}return cmfzArticles;}
}

作业:

  1. 封装工具类
  2. 使用id 删除一个上师的数据

删除一个 和 修改

/*** 删除一个 按照id  int 需要使用查询Int的Query*/
@Test
public void test6() throws IOException {IndexWriter indexWriter = LuceneUtil.getIndexWriter();/*** Term 词语 术语 学期  在Lucene指 一个不能被分词的词语 最小单位  上师  针对的是StringField进行查询* Query** 方法1:通过int删除* Range方法 是一个范围* 参数1 属性名* 参数2 开始id* 参数3 结束id* 参数4 true false 包不包含开始id* 参数5 true false 包不包含结束id** 方法2:通过String删除 假设id=123 "123"* 1.存索引的时候 需要保证Id用的是 StringField* 2.删除的时候 使用TermQuery来进行删除*/NumericRangeQuery<Integer> query = NumericRangeQuery.newIntRange("articleId", 1, 1, true, true);TermQuery termQuery = new TermQuery(new Term("articleId", "1"));indexWriter.deleteDocuments(termQuery);indexWriter.commit();indexWriter.close();
}/*** 修改*/
@Test
public void test7() throws IOException {IndexWriter indexWriter = LuceneUtil.getIndexWriter();/*** 参数1 Term对象 要修改那个id对应的数据* 参数2 Document对象  要更新的数据* 参数3 分词器*/Term articleId = new Term("articleId", "2");Document document = new Document();document.add(new StringField("articleId","2", Field.Store.YES));/*** StringField 不分词* TextField 会分词处理 需要被查询的数据 要定义为文本Field*/document.add(new TextField("articleName","上师对弟子的评价与期望", Field.Store.YES));document.add(new TextField("articleContent","春眠不觉晓", Field.Store.YES));/*** 时间 可以 long 类型  String*/document.add(new LongField("articleDate",new Date().getTime(), Field.Store.YES));indexWriter.updateDocument(articleId,document,LuceneUtil.analyzer);indexWriter.commit();indexWriter.close();
}

分词器讲解

分词器:按照一定的规则,解析文本,提取关键词

分词规则:

  1. 关键词 会被创建为索引的词 例如:橘子 背影 等
  2. 停用词 不需要被创建索引的词 例如:的 呢 了 呵 等

什么是关键词 什么是停用词 是自定义的

不同的分词器 有不同的分词规则

测试常见的分词器

package com.baizhi.lucene;import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.cjk.CJKAnalyzer;
import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.util.Version;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;import java.io.IOException;
import java.io.StringReader;/****/
public class AnalyzerTest {private String text = "百知教育,上师,窃书不能算偷……窃书!……读书人的事,能算偷么?”接连便是难懂的话";/*** 测试分词规则 标准分词器* 单个分词  每个字儿都是关键词**/@Testpublic void test1() throws IOException {test(new StandardAnalyzer(Version.LUCENE_44),text);}/*** 智能中文分词器*/@Testpublic void test2() throws IOException {test(new SmartChineseAnalyzer(Version.LUCENE_44),text);}/*** 中日韩分词器* 分词规则 两两分词*/@Testpublic void test3() throws IOException {test(new CJKAnalyzer(Version.LUCENE_44),text);}/*** ik分词器  庖丁分词器*/@Testpublic void test4() throws IOException {IKAnalyzer ikAnalyzer = new IKAnalyzer();test(ikAnalyzer,text);}/***  该方法会把分词的结果打印出来* @param analyzer  分词器对象* @param text 文本  要进行分词的文本* @throws IOException*/public static void  test(Analyzer analyzer, String text) throws IOException {System.out.println("当前分词器:--->"+analyzer.getClass().getName());TokenStream tokenStream = analyzer.tokenStream("content", new StringReader(text));tokenStream.addAttribute(CharTermAttribute.class);tokenStream.reset();while(tokenStream.incrementToken()){CharTermAttribute attribute = tokenStream.getAttribute(CharTermAttribute.class);System.out.println(attribute.toString());}tokenStream.end();int a = 1;}
}

自定义分词规则(使用IK分词器)

  1. 导入依赖

    <!--ik中文分词器-->
    <dependency><groupId>com.janeluo</groupId><artifactId>ikanalyzer</artifactId><version>2012_u6</version>
    </dependency>
    
  2. 导入配置文件

  1. 在配置文件(词典)中自定义分词规则

  1. 直接在项目中使用

高亮展示

问题:

  1. 如何实现表示? <font color='red'>上师</font>
  2. 高亮展示添加给谁? 搜索关键词处理的结果
  3. 在什么地方给 关键词 添加 标签? 数据查询出来之后

代码实现

  1. 导入依赖

    <!--高亮器-->
    <dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-highlighter</artifactId><version>4.4.0</version>
    </dependency>
    
  2. 修改查询的代码

    1. 在查询过程中创建一个高亮器

    2. 使用高亮器处理查询结果

    1. 示例代码【没有封装工具类】

      /*** 搜索* @throws ParseException* @throws IOException*/
      @Test
      public void test2() throws ParseException, IOException, InvalidTokenOffsetsException {/*** 1.准备搜索关键词*/String keywords = "朱自清的文章";/*** 2.处理搜索关键词* MultiFieldQueryParser 多列属性查询处理的对象* 参数1 Lucene的版本号* 参数2 属性名的数组* 参数3 分词器对象  需要保证和创建索引时候用的一个分词器* parse() 处理关键词 得到一个Query对象*/String[] fields = {"title","author","content"};StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_44);MultiFieldQueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_44,fields,analyzer);Query query = queryParser.parse(keywords);/*** 3.通过处理好的关键词 去 索引库中查询 得到索引(索引词+最终数据的位置信息id)*/DirectoryReader reader = DirectoryReader.open(FSDirectory.open(new File("E://lucene")));IndexSearcher searcher = new IndexSearcher(reader);/*** search 方法* 参数1 Query 对象* 参数2 期望的结果条数** TopDocs 结果集 包含了结果的数据(索引)*/TopDocs topDocs = searcher.search(query, 10);/*** 处理结果集* scoreDocs 包含有分数 和 文档对象的id(原始数据)(位置信息)*/ScoreDoc[] scoreDocs = topDocs.scoreDocs;/*** 创建高亮器* 参数1 高亮规则  要添加的样式 `<font color='red'></font>`* 参数2 搜索关键词分词的结果 再处理  QueryScorer:处理搜索关键词*/SimpleHTMLFormatter formatter = new SimpleHTMLFormatter("<font color='red'>", "</font>");QueryScorer queryScorer = new QueryScorer(query);Highlighter highlighter = new Highlighter(formatter,queryScorer);/*** 4.通过位置信息 得到数据*/for (ScoreDoc scoreDoc : scoreDocs) {System.out.println(scoreDoc.score);/*** docId 文档对象在索引库中的位置信息*/int docId = scoreDoc.doc;/*** 通过位置信息 得到数据 Document*/Document document = searcher.doc(docId);String id = document.get("id");System.out.println(id);String title = document.get("title");System.out.println(title);String author = document.get("author");/*** 通过高亮器 处理搜索结果* 参数1 分词器* 参数2 属性名* 参数3 被处理文本*/String author1 = highlighter.getBestFragment(LuceneUtil.analyzer, "author", author);System.out.println(author);System.out.println(author1);String content = document.get("content");System.out.println(content);String date = document.get("date");long l = Long.parseLong(date);Date date1 = new Date(l);System.out.println(date1);String s = DateTools.dateToString(date1, DateTools.Resolution.DAY);System.out.println(s);}
      }
      

高亮的问题

解决:非空判断

项目集成

作业:

  1. 将之前的分词器替换IK分词器
  2. 练习高亮的代码
  3. 完成项目集成 方案1

方案1【作业】:

  1. 重置索引库功能
  2. 高级检索功能 就是全文检索 将查询的结果展示在table中(不需要考虑分页)

方案2【了解】:

  1. 搜索引擎的入口

  1. 搜索结果展示页 【内容来自索引库】

  1. 结果详情页 【内容来自数据库】

问题解决

总结

  1. 应用场景出发:用户输入的关键词 千奇百怪 不可能做到和数据库的原始数据 一一对应 所以通过模糊匹配很难的到结果
  2. 模糊匹配的缺点
  3. 全文检索
    1. 索引创建
    2. 查询过程
  4. 全文特点
  5. 代码环节
    1. 索引的创建

      1. 准备数据 将数据封装在 Document 对象 文档对象
      2. 将数据写出到 索引库 在写的同时Lucene会自动的做分词处理 并且 创建索引
        1. 索引库位置的定义
        2. 索引写出的参数的定义 版本 分词器
      3. 将文档对象交给 索引写出对象
      4. 提交到索引库
      5. 释放资源
    2. 通过关键词查询
      1. 获取搜索关键词
      2. 处理搜索关键词
        1. 需要定义 要查询哪些属性 使用什么分词器
        2. 需要保证 查询时的分词器 和 创建索引时的分词器 是同一个
      3. 通过索引查询对象 读取索引库 直接调用方法查询 得到结果集
      4. 处理结果集 得到 文档对象的id (位置信息)
      5. 通过文档对象的id 再次查询 得到原始的数据 (Document 对象 )
    3. 索引库的数据结构
      1. 两个区域:索引区和元数据区
      2. Field.Store.YES 和 Field.Store.NO 区别
    4. 封装工具类 【常规操作】
    5. 删除和修改
      1. 根据 id 删除

        1. IntField
        2. StringField
    6. 分词器
      1. 分词规则

        1. 关键词
        2. 停用词
      2. IK分词器
    7. 高亮展示 (搜索结果中关键词变色处理)
    8. 项目集成
      1. 后台集成方案:表格展示
      2. web端方案:搜索页面—>搜索结果展示页面【来自索引库】—>结果详情页【来自数据库】

补充参考资料

  1. 第三阶段补充课程 资料
  2. 博客 全文检索的原理 【了解】

全文检索

  1. 索引创建
  2. 查询过程
  3. 全文特点
  4. 代码环节
    1. 索引的创建

      1. 准备数据 将数据封装在 Document 对象 文档对象
      2. 将数据写出到 索引库 在写的同时Lucene会自动的做分词处理 并且 创建索引
        1. 索引库位置的定义
        2. 索引写出的参数的定义 版本 分词器
      3. 将文档对象交给 索引写出对象
      4. 提交到索引库
      5. 释放资源
    2. 通过关键词查询
      1. 获取搜索关键词
      2. 处理搜索关键词
        1. 需要定义 要查询哪些属性 使用什么分词器
        2. 需要保证 查询时的分词器 和 创建索引时的分词器 是同一个
      3. 通过索引查询对象 读取索引库 直接调用方法查询 得到结果集
      4. 处理结果集 得到 文档对象的id (位置信息)
      5. 通过文档对象的id 再次查询 得到原始的数据 (Document 对象 )
    3. 索引库的数据结构
      1. 两个区域:索引区和元数据区
      2. Field.Store.YES 和 Field.Store.NO 区别
    4. 封装工具类 【常规操作】
    5. 删除和修改
      1. 根据 id 删除

        1. IntField
        2. StringField
    6. 分词器
      1. 分词规则

        1. 关键词
        2. 停用词
      2. IK分词器
    7. 高亮展示 (搜索结果中关键词变色处理)
    8. 项目集成
      1. 后台集成方案:表格展示
      2. web端方案:搜索页面—>搜索结果展示页面【来自索引库】—>结果详情页【来自数据库】

补充参考资料

  1. 第三阶段补充课程 资料
  2. 博客 全文检索的原理 【了解】

Lucene架构学习相关推荐

  1. javaweb k8s_K8S微服务核心架构学习指南 ASP.NET Core微服务基于K8S 架构师必备Kubernetes教程...

    K8S微服务核心架构学习指南 ASP.NET Core微服务基于K8S 架构师必备Kubernetes教程 课程内容是关于Kubernetes微服务架构学习课程,基于K8S开展ASP.NET核心进行微 ...

  2. ZT Android4.2蓝牙基础架构学习

    Android4.2蓝牙基础架构学习 分类: Jellybean Bluetooth Bluetooth 2013-10-13 23:58 863人阅读 评论(3) 收藏 举报 androidblue ...

  3. 时序图 分支_BOOM微架构学习(1)——取指单元与分支预测

    之前在RISC-V的"Demo"级项目--Rocket-chip一文中曾经简介过BOOM处理器的流水线,这次我们开始一个系列,深入学习一下BOOM的微架构,这样对于乱序执行的超标量 ...

  4. bpmn2.0业务过程模型和符号_IT帮业务架构学习小组学习内容

    关于学习内容,担心大家学完的可能不多,所以考虑是先选择一小部分来学.但考虑到业务架构属于组织级学科,本身就要求体系全面,所以还是决定把全套内容放入到本期学习.下面我列举一下我们这8个月在业务架构自主学 ...

  5. SpringCloud微服务架构学习(二)常见的微服务架构

    SpringCloud微服务架构学习(二)常见的微服务架构 1.Dubbo 阿里开源微服务框架 官网地址:http://dubbo.apache.org/en-us/ 简介: Dubbo是阿里巴巴SO ...

  6. 《InsideUE4》GamePlay架构学习_Level和World

    <InsideUE4>GamePlay架构学习 Level和World 前话 Unity To UE 思考 为什么AWorldSettings[0]的位置,而ALevelScriptAct ...

  7. MIPS架构学习笔记

    MIPS架构学习笔记 来源: ChinaUnix博客 日期: 2007.03.13 23:18 (共有条评论) 我要评论 MIPS架构学习笔记                              ...

  8. 高性能架构学习路线图-分布式架构演进,mybatis一对一一对多面试题

    架构演进一: 早期雏形 架构演进二: 数据库开发(LAMP特长) 架构演进三:  javaweb的雏形 架构演进四:  javaweb的集群发展​ 架构演进五:  javaweb的分布式发展 架构演进 ...

  9. 高性能架构学习路线图-分布式架构演进

    目录 一.分布式架构学习路线图 二.计算机软件发展历史 三.技术架构演进史 架构演进一: 早期雏形 架构演进二: 数据库开发(LAMP特长) 架构演进三:  javaweb的雏形 架构演进四:  ja ...

最新文章

  1. 内嵌IE网页窗口中消除IE默认脚本设置影响的方法
  2. FFmpeg再学习 -- FFmpeg+SDL+MFC实现图形界面视频播放器
  3. apache应用进阶
  4. D3DCOLOR与D3DXCOLOR
  5. mysql 日志节点恢复_基于binlog二进制日志的MySQL恢复笔记
  6. 最后一公里极速配送 - 阿里云算法大赛总结
  7. 2018: 跑图(深搜)
  8. C语言 · 9-1九宫格
  9. POJ3080 ZOJ2784 UVALive3628 Blue Jeans题解
  10. 深度优先遍历(DFS)- Letter CasePermutation - Combinations
  11. 微信扫一扫服务器地址,微信扫一扫
  12. .NET-3.Xamarin学习与总结
  13. 计算机408考研 思维导图 知识整理
  14. SQL SERVER数据库三种数据插入方式
  15. 桌面计算机地址栏在哪,电脑窗口地址栏清理
  16. cond怎么读_cond condition是什么意思
  17. 网页不能自动播放视频、音频的解决方案
  18. php 判断字符串乱码,php如何检测乱码字符
  19. 例3.2、计算存款利息。有1000元,想存一年。有三种方法可选:(1)活期,年利率为r1;(2)一年期定期,年利率为r2;(3)存两次半年定期,年利率为r3。请分别计算出一年后按3种方法所得到的本息和
  20. 最不可思议的巧合,这些电影一定是穿越者拍的了!

热门文章

  1. 利用伪元素给图片在鼠标悬停时添加背景图片
  2. 【激光雷达点云障碍物检测】(一)滤波部分
  3. 超简单 CameraX 人脸识别效果封装
  4. 计算机网络基本概念,计算机网络基本概念【笔记】
  5. Docsify保姆级教程
  6. Nature雄文指引绿色金融研究-内附丰富低碳数据
  7. 服务器共享文件怎么自动备份,如何用批处理把域的文件服务器中的共享资源备份到另一台电脑中...
  8. 解决vue渲染时闪烁{{}}的问题
  9. windows/NBTSTAT,linux/nmblookup命令详解,查询NetBIOS名
  10. endnote参考文献格式