全文检索概述

数据分类

  • 结构化数据:具有固定格式或者长度有限的数据,例如数据库中的表。【SQL语句】

  • 非结构化数据:与结构化数据对立,例如:邮件、网页、word文档。【数据扫描、全文检索】

  • 半结构化数据:介于两者之间,例如xml或者json格式的数据。

全文检索过程


反向索引(倒排表):由字符串到文件的映射是文件到字符串映射的反向过程。

索引创建

索引检索

Lucene数学模型

文档、域、词元

文档是Lucene搜索和索引的原子单位,文档为包含一个或者多个的容器,而域则是依次包含“真正的”被搜索的内容,域值通过分词技术处理,得到多个词元

For Example,一篇小说(斗破苍穹)信息可以称为一个文档,小说信息又包含多个域,例如:标题(斗破苍穹)、作者、简介、最后更新时间等等,对标题这个域采用分词技术又可以得到一个或者多个词元(斗、破、苍、穹)。

词元权重计算

  • Term Frequency(tf):此term在文档中出现的次数,tf越大则该词元越重要

  • Document Frequency(df):有多少文档包含此term,df越大该词元越不重要

空间向量模型如下:

计算夹角的余弦值,夹角越小,余弦值越大,分值越大,从而相关性越大。

Lucene文件结构

层次结构

  • index:一个索引存放在一个目录中;

  • segment:一个索引中可以有多个段,段与段之间是独立的,添加新的文档可能产生新段,不同的段可以合并成一个新段;

  • document:文档是创建索引的基本单位,不同的文档保存在不同的段中,一个段可以包含多个文档;

  • field:域,一个文档包含不同类型的信息,可以拆分开索引;

  • term:词,索引的最小单位,是经过词法分析和语言处理后的数据。

正向信息

按照层次依次保存了从索引到词的包含关系:index-->segment-->document-->field-->term。

反向信息

反向信息保存了词典的倒排表映射:term-->document

配置Lucene开发环境

Lucene是ASF的开源项目,最新版本是5.2.1,但是鉴于网络上大多数教程使用的是Lucene 4,在本文中使用的版本是Lucene 4.3.1,下载解压,到对应目录找到以下的jar包并添加到构建路径中。

如果使用maven其maven依赖如下:

<dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-core</artifactId><version>4.3.1</version>
</dependency>
<dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-queryparser</artifactId><version>4.3.1</version>
</dependency>
<dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-queries</artifactId><version>4.3.1</version>
</dependency>
<dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-highlighter</artifactId><version>4.3.1</version>
</dependency>
<dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-analyzers-smartcn</artifactId><version>4.3.1</version>
</dependency>
<dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-analyzers-common</artifactId><version>4.3.1</version>
</dependency>

Lucene常用功能介绍

索引创建

创建索的关键类

创建索引的示例代码:

/*** 索引创建*/
@Test
public void createIndex() {// 创建一个分词器(指定Lucene版本)Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_43);    // IndexWriter配置信息(指定Lucene版本和分词器)IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_43, analyzer); // 设置索引的打开方式indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);// 创建Directory对象和IndexWriter对象Directory directory = null;IndexWriter indexWriter = null;try {directory = FSDirectory.open(new File("Lucene_index/test"));// 检查Directory对象是否处于锁定状态(如果锁定则进行解锁)if (IndexWriter.isLocked(directory)) {IndexWriter.unlock(directory);}indexWriter = new IndexWriter(directory, indexWriterConfig);} catch (IOException e) {e.printStackTrace();}// 创建测试文档并为其添加域Document doc1 = new Document();doc1.add(new StringField("id", "abcde", Store.YES));                // 添加一个id域,域值为abcdedoc1.add(new TextField("content", "使用Lucene实现全文检索", Store.YES)); // 文本域doc1.add(new IntField("num", 1, Store.YES));                         // 添加数值域// 将文档写入索引try {indexWriter.addDocument(doc1);} catch (IOException e) {e.printStackTrace();}Document doc2 = new Document();doc2.add(new StringField("id", "yes", Store.YES));                  doc2.add(new TextField("content", "Docker容器技术简介", Store.YES)); doc2.add(new IntField("num", 2, Store.YES));                       try {indexWriter.addDocument(doc2);} catch (IOException e) {e.printStackTrace();}// 将IndexWriter提交try {indexWriter.commit();} catch (IOException e) {e.printStackTrace();} finally{try {indexWriter.close();directory.close();} catch (IOException e) {e.printStackTrace();}}
}

生成的索引文件如下:

索引检索

索引检索关键类

利用以下的检索程序对前面创建的索引进行检索:

/*** 索引检索*/
@Test
public void searchIndex(){Directory directory = null;DirectoryReader dReader = null;try {directory = FSDirectory.open(new File("Lucene_index/test"));  // 索引文件dReader = DirectoryReader.open(directory);                      // 读取索引文件IndexSearcher searcher = new IndexSearcher(dReader);          // 创建IndexSearcher对象Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_43);    // 指定分词技术(标准分词-与创建索引时使用的分词技术一致)// 创建查询字符串(指定搜索域和采用的分词技术)QueryParser parser = new QueryParser(Version.LUCENE_43, "content", analyzer);Query query = parser.parse("Docker");                           // 创建Query对象(指定搜索词)// 检索索引(指定前10条)TopDocs topDocs = searcher.search(query, 10);if (topDocs != null) {System.out.println("符合条件的文档总数为:" + topDocs.totalHits);for (int i = 0; i < topDocs.scoreDocs.length; i++) {Document doc = searcher.doc(topDocs.scoreDocs[i].doc);System.out.println("id = " + doc.get("id") + ",content = " + doc.get("content") + ",num = " + doc.get("num"));}}} catch (IOException e) {e.printStackTrace();} catch (ParseException e) {e.printStackTrace();} finally{try {dReader.close();directory.close();} catch (IOException e) {e.printStackTrace();}}
}

运行结果:

Lucene分词器

常见分词器

其中IKAnalyzer需要下载专门的jar包

/*** 常见分词器*/
@Test
public void testAnalyzer(){final String str = "利用Lucene 实现全文检索";Analyzer analyzer = null;analyzer = new StandardAnalyzer(Version.LUCENE_43);   // 标准分词print(analyzer, str);analyzer = new IKAnalyzer();                           // 第三方中文分词print(analyzer, str);analyzer = new WhitespaceAnalyzer(Version.LUCENE_43);   // 空格分词print(analyzer, str);analyzer = new SimpleAnalyzer(Version.LUCENE_43);      // 简单分词print(analyzer, str);analyzer = new CJKAnalyzer(Version.LUCENE_43);         // 二分法分词print(analyzer, str);analyzer = new KeywordAnalyzer();                     // 关键字分词print(analyzer, str);analyzer = new StopAnalyzer(Version.LUCENE_43);       //被忽略词分词器print(analyzer, str);}/*** 该方法用于打印分词器及其分词结果* @param analyzer 分词器* @param str 需要分词的字符串*/
public void print(Analyzer analyzer,String str){StringReader stringReader = new StringReader(str);try {TokenStream tokenStream = analyzer.tokenStream("", stringReader);            // 分词tokenStream.reset();CharTermAttribute term = tokenStream.getAttribute(CharTermAttribute.class); // 获取分词结果的CharTermAttributeSystem.out.println("分词技术:" + analyzer.getClass());while (tokenStream.incrementToken()) {System.out.print(term.toString() + "|");}System.out.println();} catch (IOException e) {e.printStackTrace();}
}

运行结果:

Query创建



/*** 创建Query*/
@Test
public void createQuery(){String key = "JAVA EE Lucene案例开发";String field = "name";String[] fields = {"name","content"};Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_43); // 分词器// 单域查询QueryParser parser1 = new QueryParser(Version.LUCENE_43, field, analyzer);Query query1 = null;try {query1 = parser1.parse(key); // 使用QueryParser创建Query} catch (ParseException e) {e.printStackTrace();}System.out.println(QueryParser.class + query1.toString());// 多域查询MultiFieldQueryParser parser2 = new MultiFieldQueryParser(Version.LUCENE_43, fields, analyzer);try {query1 = parser2.parse(key);} catch (ParseException e) {e.printStackTrace();}System.out.println(QueryParser.class + query1.toString());// 短语查询query1 = new TermQuery(new Term(field, key));System.out.println(TermQuery.class + query1.toString());// 前缀查询query1 = new PrefixQuery(new Term(field, key));System.out.println(PrefixQuery.class + query1.toString());// 短语查询PhraseQuery query2 = new PhraseQuery();query2.setSlop(2); // 设置短语间的最大距离是2query2.add(new Term(field, "Lucene"));query2.add(new Term(field, "案例"));System.out.println(PhraseQuery.class + query2.toString());// 通配符查询query1 = new WildcardQuery(new Term(field, "Lucene?"));System.out.println(WildcardQuery.class + query1.toString());// 字符串范围搜索query1 = TermRangeQuery.newStringRange(field, "abc", "azz", false, false);System.out.println(TermRangeQuery.class + query1.toString());// 布尔条件查询BooleanQuery query3 = new BooleanQuery();query3.add(new TermQuery(new Term(field, "Lucene")),Occur.SHOULD); // 添加条件query3.add(new TermQuery(new Term(field, "案例")),Occur.MUST); query3.add(new TermQuery(new Term(field, "案例")),Occur.MUST_NOT); System.out.println(BooleanQuery.class + query3.toString());
}

运行结果:

IndexSearcher常用方法

检索关键类

Lucene学习笔记相关推荐

  1. Lucene学习笔记(1)

    Lucene学习笔记 可以搜索文本文件,理论上可以搜索任何类型的数据.只要先把数据转化为文本,就可以对数据进行索引和搜索. 使用了反向索引的机制,维护一个词/短语的表,对于每个词和短语都有一个链表描述 ...

  2. lucene学习笔记_学习Lucene

    lucene学习笔记 我目前正在与一个团队合作,开始一个基于Lucene的新项目. 虽然大多数时候我会争论使用Solr还是Elasticsearch而不是简单的Lucene,但这是一个有意识的决定. ...

  3. Lucene 学习笔记(一)

    2019独角兽企业重金招聘Python工程师标准>>> 最近,由于需要做到搜索功能,但是搜索功能里面,涉及的关系比较复杂,如果通过sql语言来查询,效率十分低下,所以便开始研究了下j ...

  4. 搜索-Lucene学习笔记

    1 全文检索 和 索引 1.1 索引 将非结构化数据中的一部分信息 取出来,重新组织,使其变得有一定结构,然后对此有 一定结构的数据进行搜索,从而达到搜索相对较快的目的.这部分从非结构化数据中 取出的 ...

  5. Lucene学习笔记:Field.Store.* 域存储选项

    2019独角兽企业重金招聘Python工程师标准>>> Store.YES: 指定存储域值.该情况下,原始的字符串值全部都被保存在索引中,并可以由IndexReader类恢复.该选项 ...

  6. Hadoop学习笔记一 简要介绍

    Hadoop学习笔记一 简要介绍 这里先大致介绍一下Hadoop.     本文大部分内容都是从官网Hadoop上来的.其中有一篇介绍HDFS的pdf文档,里面对Hadoop介绍的比较全面了.我的这一 ...

  7. 基于Solr的空间搜索学习笔记

    基于Solr的空间搜索学习笔记 在Solr中基于空间地址查询主要围绕2个概念实现: (1) Cartesian Tiers 笛卡尔层 Cartesian Tiers是通过将一个平面地图的根据设定的层次 ...

  8. 学习笔记:The Log(我所读过的最好的一篇分布式技术文章

     学习笔记:The Log(我所读过的最好的一篇分布式技术文章)         前言 这是一篇学习笔记. 学习的材料来自Jay Kreps的一篇讲Log的博文. 原文很长,但是我坚持看完了,收获 ...

  9. Solr 6.7学习笔记(04)-- Suggest

    当我们使用baidu或者Google时,你输入很少的字符,就会自动跳出来一些建议选项,在Solr里,我们称之为Suggest,在solrconfig.xml里做一些简单的配置,即可实现这一功能.配置如 ...

最新文章

  1. 微信基础服务肯定不收费
  2. 开启一个新的spyder窗口
  3. Spark学习之Spark RDD算子
  4. pmp每日三题(2022年2月28日)
  5. cocos2d-x初探学习笔记(3)--动作(CCAction)
  6. php上传,PHP-文件上传和下载「程序员培养之路第三十八天」
  7. 网络编程(part11)--socket模块方法及socket套接字属性
  8. jetty java 禁用目录列表_java – 如何禁用Jetty的WebAppContext目录列表?
  9. leetcode题解767-重构字符串
  10. SpingMVC Model 和ModelAndView,以及从参数的设置和接收
  11. ubuntu 下 maven安装
  12. 如何用Python快速实现区块链?
  13. 使用内存硬盘(tmpfs)来加速你的网站
  14. ubuntu 常用配置
  15. 计算机机房维护与管理,计算机机房的管理与维护.doc
  16. HTML期末作业我的家乡静态网页设计
  17. 计算机word怎么写,电脑word怎么用?
  18. MySQL面试夺命连环27问
  19. 计算机图形学与OpenGL
  20. 偷偷告诉你中国小姐姐的真实Size!!

热门文章

  1. 7-273 插入排序还是归并排序 (25 分)
  2. R7-5 求矩阵各行元素之和 (15 分)
  3. 7-30 查询水果价格 (15 分)
  4. 项目部署—Linux命令安装redis
  5. 广州计算机专业王健,王健 - 教师简历 CV- 武汉大学计算机学院
  6. go java jsonrpc_使用golang 实现JSON-RPC2.0
  7. 探索 Word 2007 开发(四):上传图片
  8. ThreadLocal 在web环境下使用的边界问题
  9. JavaScript函数之实际参数对象(arguments) / callee属性 / caller属性 / 递归调用 / 获取函数名称的方法...
  10. 一起学JUCE之HashMap