欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

lucene&solr学习

程序员文章站 2022-07-01 09:28:09
...

一、什么是全文检索

对源数据创建索引,在索引上搜索这个过程就是全文检索
创建索引+查询

数据分类

1、结构化数据:

有固定格式和有限长度,比如Oracle或mysql表中的数据,使用SQL语句查询结构化数据,速度快如果数据量大时,可以在数据库中创建索引,但是此时创建的索引是不支持模糊查询,需要创建另外一套索引库

2、非结构化数据:

每有固定格式也没 有限长度 比如:磁盘上的文件 word excel ppt pdf txt查询非结构化数据:1、目测(顺序扫描法) 2、IO读取 3、全文检索

二、全文检索的应用场景

1、搜索引擎 谷歌 百度 360 搜狗
2、站内搜索 淘宝、京东、微博、论坛

三、怎么实现全文检索

使用Lucene实现

四、Lucene简介

是Apache下的开源用来实现全文检索的工具包,API
lucene是底层 solr是对lucene的再次封装

五、Lucene实现全文检索的流程

1、创建索引

1)、获取源文档

什么是源文档?
场景1:搜索引擎:指的是互联网上的所有网页
场景2:站内搜索:磁盘上的文件或表中的数据
获取源文档的方式?
场景1:搜索引擎: 网络爬虫
场景2:站内搜索 :IO流、sql查询

2)、构建文档对象(Document)

一个Document对象中放的是:一个网页内容、或一个文件内容、或表中的一列数据

3)、对内容分词(分析文档)

举例:①、一个文件包含的信息:
		     1、文件名称
		     2、文件大小
		     3、文件路径
		     4、文件内容
	   ②、一个网页包含的信息:
		     1、网络地址URL
		     2、网页标题
		     3、网页内容
	   ③、一条数据包含的信息:
		     一条数据每个列的内容
		     有多少列就应该创建多少个域
          分词效果:
      原内容:The Spring Framework provides a comprehensive programming and configuration model.
	分词的处理方式:
	1、按空格分词
	2、处理大小写
	3、停用词
	4、标点符号
	最后的效果:  term
	    name:spring
		content:spring
		content:framework
		content:provides
		content:comprehensive
		content:programming
		content:configuration
		content:model

4)、创建索引(存储)

分析后的格式: name:spring name自定义的域名称,spring,此域中的值 name:spring就是一个词汇term
一个文档中可以有多个域,不同的文档可以有不同的域
创建索引是对语汇单元索引,通过词语找文档,这种索引的结构叫倒排索引结构。比如:新华字典

2、查询索引

1)、用户查询接口:就是用户输入关键字的位置
2)、创建查询
3)、执行查询
4)、渲染结果

六、Lucene入门案例

核心的jar:lucene-core-4.10.3.jar、lucene-analyzers-common-4.10.3.jar
commons-io.jar

1、创建索引

场景:给磁盘的文件创建索引
步骤:

public class IndexWriterTest {
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		// 1、指定索引库位置
		Directory directory = FSDirectory.open(new File("D:\\class297\\indexRepo"));
		// 指定分词器
		Analyzer analyzer = new StandardAnalyzer();//标准的分词器
		IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, analyzer);// Version.LATEST最新版本
		// 2、创建写入索引的对象
		IndexWriter indexWriter = new IndexWriter(directory, config);
		// 3、获取源文档
		File srcFile = new File("D:\\searchsource");
		File[] listFiles = srcFile.listFiles();
		for (File file : listFiles) {
			Document doc = new Document();
			// 1、文件名称
			String fileName = file.getName();
			Field nameField = new TextField("name", fileName, Store.YES);// Store.YES是否存储原内容
			doc.add(nameField);
			// 2、文件大小
			long fileSize = FileUtils.sizeOf(file);
			Field sizeField = new TextField("size", fileSize + "", Store.YES);
			doc.add(sizeField);
			// 3、文件路径
			String filePath = file.getPath();
			Field pathField = new TextField("path", filePath, Store.YES);
			doc.add(pathField);
			// 4、文件内容
			String fileContent = FileUtils.readFileToString(file);
			Field contentField = new TextField("content", fileContent, Store.YES);
			doc.add(contentField);
			// 4、把文档写入索引库
			indexWriter.addDocument(doc);
		}
		// 5、关闭资源
		indexWriter.close();
	}
}

使用luke工具查看索引文件

2、查询索引步骤

public class IndexReaderTest {
	public static void main(String[] args) throws Exception {
		// 1、指定索引库的位置
		Directory directory = FSDirectory.open(new File("D:\\class297\\indexRepo"));
		// 2、创建读取索引对象
		IndexReader indexReader = DirectoryReader.open(directory);
		// 3、创建查询索引对象
		IndexSearcher searcher = new IndexSearcher(indexReader);
		// 4、执行查询方法 query:指定条件
		Query query = new TermQuery(new Term("content", "spring"));
		// 5、获取查询结果, n:查询数据量的限制
		TopDocs topDocs = searcher.search(query, 100);
		System.out.println("总记录数:" + topDocs.totalHits);
		ScoreDoc[] scoreDocs = topDocs.scoreDocs;//文档
		for (ScoreDoc scoreDoc : scoreDocs) {
			int docID = scoreDoc.doc;//文档id
			Document doc = searcher.doc(docID);
			// 获取文档的内容
			System.out.println("文件名:" + doc.get("name"));
			System.out.println("文件大小:" + doc.get("size"));
			System.out.println("文件路径:" + doc.get("path"));
			//System.out.println("文件内容:"+doc.get("content"));
			System.out.println("-----------------------------------------------");
		}
		// 6、关闭资源
		indexReader.close();
	}
}

七、分词器 Analyzer 每个分词器tokenStream方法

// Analyzer analyzer = new StandardAnalyzer(); //英文按照空格分词,中文一个字一个字
// Analyzer analyzer = new CJKAnalyzer(); //中文两个字两个字
// 需要导入lucene-analyzers-smartcn-4.10.3.jar
// Analyzer analyzer = new SmartChineseAnalyzer(); //中文还可以,但是英文容易出现缺字母

// 第三方分词器IK-Analyzer
// 需要导入jar IKAnalyzer2012FF_u1.jar
Analyzer analyzer = new IKAnalyzer();

八、分词器的使用时机

1、需要查询就需要分词
2、查询时也需要分词

九、索引的维护

是否分析:是否拆词 是否索引:是否用来检索 是否存储:是否要用来展示

Field属性 是否分析(分词) 是否索引 是否存储 举例
StringField N Y N or Y 手机号、身份证号
LongField Y Y N or Y 商品的价格、文件大小
StoredField N N Y 网页地址URL、文件路径
TextFiled Y Y N or Y 网页内容、文件内容

1、删除操作

indexWriter.deleteAll();//慎用
indexWriter.deleteDocuments(new Term("name", "spring"));

2、修改操作

 indexWriter.updateDocument(term, doc);

3、查询操作

 1)、TermQuery   语法:   name:apache
 2)、MatchAllDocsQuery  语法: *:*
 3)、NumericRangeQuery  语法:  size:[100 TO 1000] 但是luke不支持数值的范围查询   solr支持的
 4)、BooleanQuery    
 Query query1 = new TermQuery(new Term("name", "apache"));
 Query query2 = new TermQuery(new Term("content", "spring"));
 query.add(query1, Occur.MUST);
 query.add(query2, Occur.MUST);  语法:  +name:apache +content:spring

 query.add(query1, Occur.MUST);
 query.add(query2, Occur.SHOULD);语法:  +name:apache content:spring


  query.add(query1, Occur.MUST);
  query.add(query2, Occur.MUST_NOT); 语法: +name:apache -content:spring

  query.add(query1, Occur.MUST_NOT);
  query.add(query2, Occur.MUST_NOT);  此查询无意义

 5)、QueryParser  分词后查询            需要导 lucene-queryparser-4.10.3.jar
 语法: name:lucene name:project name:apache
 6)、MulitFieldQueryParser
 语法:(name:lucene content:lucene) (name:project content:project) (name:apache content:apache)

十、相关度排序(竞价排序)

name:apache
	apache lucene.txt
	Apache_Lucene_README.txt
	Welcome to the Apache Solr project.txt
打分:默认分值是1,设置越高排名靠前
Field.setBoost(分数);