互联网框架day15(搜索lucene、Elasticsearch)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2.1倒序索引的计算步骤

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.1lucene的分词器测试
引入依赖

<dependency><!--查询相关jar包  -->
    	<groupId>org.apache.lucene</groupId>
    	<artifactId>lucene-queryparser</artifactId>
    	<version>6.0.0</version>
    </dependency>
    <dependency><!-- lucene自带只能中文分词器jar包 -->
    	<groupId>org.apache.lucene</groupId>
    	<artifactId>lucene-analyzers-smartcn</artifactId>
    	<version>6.0.0</version>
    </dependency>
    <dependency><!--测试用到的lucene工具包  -->
    	<groupId>org.apache.lucene</groupId>
    	<artifactId>lucene-analyzers-common</artifactId>
    	<version>6.0.0</version>
    </dependency>
    <dependency><!--测试用到的lucene核心包  -->
    	<groupId>org.apache.lucene</groupId>
    	<artifactId>lucene-core</artifactId>
    	<version>6.0.0</version>
    </dependency>

在这里插入图片描述
分词器的测试代码
分词处理获取文本的属性

package cn.tedu.lucene.test;

import java.io.IOException;
import java.io.StringReader;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.analysis.core.SimpleAnalyzer;
import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.junit.Test;

//分词器测试
public class AnalyzerTest {
	/**
	 * 处理分词器的分词过程
	 * 打印展示文本属性  词性
	 * @throws IOException 
	 */
	
	public void printTerm(Analyzer analyzer,String msg) throws IOException{
		//获取字符串流
		StringReader reader=new StringReader(msg);
		//可以通过analyzer对象调用方法
		//不同实现类底层分词逻辑不同
		TokenStream tokenStream = analyzer.tokenStream("test", reader);
		//filedName:域属性名称,分词测试没有具体的意义
		//将分词的文本的属性打印词项的词,需要指针重置
		tokenStream.reset();
		CharTermAttribute attribute = tokenStream.getAttribute(CharTermAttribute.class);
		
		while(tokenStream.incrementToken()){
			System.out.println(attribute.toString());
			//词项
		}
	}
	
	//实现测试方法,传递使用不同的分词器
	@Test
	public void run() throws IOException{
		//准备一个计算分词的文本
		String msg="你是喜欢王者荣耀,还是喜欢英雄联盟";
		//使用不同的分词器实现类
		Analyzer a1=new SimpleAnalyzer();//根据标点切分句子
		Analyzer a2=new WhitespaceAnalyzer();//根据空格切分,句子,词,字
		Analyzer a3=new StandardAnalyzer();//根据字符切分,字
		Analyzer a4=new SmartChineseAnalyzer();//根据中文词切分
		System.out.println("*********简单*********");
		printTerm(a1, msg);
		System.out.println("*********空格*********");
		printTerm(a2, msg);
		System.out.println("*********标准*********");
		printTerm(a3, msg);
		System.out.println("*********中文*********");
		printTerm(a4, msg);
		
	}
}

3.2IK分词器
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

<!--ik导入本地管理的分词器  -->
    <dependency><!--测试用到的lucene核心包 -->
    	<groupId>cn.tedu</groupId>
    	<artifactId>ik-analyzer</artifactId>
    	<version>u6</version>
    	<scope>system</scope>
    	<systemPath>D://ali_repo/IKAnalyzer2012_u6.jar</systemPath>
    </dependency>
IKAnalyzer2012_u6.jar下载
http://lxw1234.com/archives/2015/07/422.htm
下载地址:https://code.google.com/p/ik-analyzer/downloads/list
这个地址估计大家不方便,上传了一份到网盘:
http://pan.baidu.com/s/1i3eXhAH
密:34w6

测试代码

package cn.tedu.lucene.test;

import java.io.IOException;

import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;
/**
 * 
 * 如果在使用中出现错误
 *	java.lang.AssertionError: TokenStream implementation classes or at least their incrementToken() implementation must be final
 *	那么为IKTokenizer6x class 加入final关键字
 *
 */
public final class  IKTokenizer6x extends Tokenizer {
	// IK分词器实现
	private IKSegmenter _IKImplement;
	// 词元文本属性
	private final CharTermAttribute termAtt;
	// 词元位移属性
	private final OffsetAttribute offsetAtt;
	// 词元分类属性(该属性分类参考org.wltea.analyzer.core.Lexeme中的分类常量)
	private final TypeAttribute typeAtt;
	// 记录最后一个词元的结束位置
	private int endPosition;
 
	// Lucene 6.x Tokenizer适配器类构造函数;实现最新的Tokenizer接口
	public IKTokenizer6x(boolean useSmart) {
		super();
		offsetAtt = addAttribute(OffsetAttribute.class);
		termAtt = addAttribute(CharTermAttribute.class);
		typeAtt = addAttribute(TypeAttribute.class);
		_IKImplement = new IKSegmenter(input, useSmart);
	}
 
	@Override
	public boolean incrementToken() throws IOException {
		// 清除所有的词元属性
		clearAttributes();
		Lexeme nextLexeme = _IKImplement.next();
		if (nextLexeme != null) {
			// 将Lexeme转成Attributes
			// 设置词元文本
			termAtt.append(nextLexeme.getLexemeText());
			// 设置词元长度
			termAtt.setLength(nextLexeme.getLength());
			// 设置词元位移
			offsetAtt.setOffset(nextLexeme.getBeginPosition(), nextLexeme.getEndPosition());
			// 记录分词的最后位置
			endPosition = nextLexeme.getEndPosition();
			// 记录词元分类
			typeAtt.setType(nextLexeme.getLexemeText());
			// 返会true告知还有下个词元
			return true;
		}
		// 返会false告知词元输出完毕
		return false;
	}
 
	@Override
	public void reset() throws IOException {
		super.reset();
		_IKImplement.reset(input);
	}
 
	@Override
	public final void end() {
		int finalOffset = correctOffset(this.endPosition);
		offsetAtt.setOffset(finalOffset, finalOffset);
	}
}
package cn.tedu.lucene.test;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.Tokenizer;

public class IKAnalyzer6x extends Analyzer {
	private boolean useSmart;
 
	public boolean useSmart() {
		return useSmart;
	}
 
	public void setUseSmart(boolean useSmart) {
		this.useSmart = useSmart;
	}
 
	// IK分词器Lucene Analyzer接口实现类;默认细粒度切分算法
	public IKAnalyzer6x() {
		this(false);
	}
 
	// IK分词器Lucene Analyzer接口实现类;当为true时,分词器进行智能切分
	public IKAnalyzer6x(boolean useSmart) {
		super();
		this.useSmart = useSmart;
	}
 
	// 重写最新版本的createComponents;重载Analyzer接口,构造分词组件
	@Override
	protected TokenStreamComponents createComponents(String fieldName) {
		Tokenizer _IKTokenizer = new IKTokenizer6x(this.useSmart());
		return new TokenStreamComponents(_IKTokenizer);
	}
}

在这里插入图片描述
1.1创建索引

package cn.tedu.lucene.index;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.DoublePoint;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.store.FSDirectory;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;


import cn.tedu.lucene.test.IKAnalyzer6x;

/**
 * lucene提供创建倒排索引算法的所有工具
 * 包内容,直接使用工具包实现索引的创建
 * @author 在路上
 *
 */
public class CreateIndex {
/*
 * 1.确定索引的输出位置
 * 2.准备一个具备使用IK分词器输出对象流对象writer
 * 3.内存的document(读取元数据封装)数据封装
 * 4.输出写入到索引文件
 * 域的类型(文本,数字),存储的索引数据
 */
	@Test
	public void createIndex() throws Exception{
		//确认一个输出文件夹位置作为索引
		Path path=Paths.get("d://index01");
		//交给lucene的目录工具类
		FSDirectory dir = FSDirectory.open(path);
		//创建输出对象对应的配置对象
		IndexWriterConfig config=new IndexWriterConfig(new IKAnalyzer6x());
		//定义写出时的方式APPEND  CREATE  CREATE_OR_APPEND
		config.setOpenMode(OpenMode.CREATE);
		//配合dir路径创建输出write
		IndexWriter writer=new IndexWriter(dir, config);
		//封装document  2各document
		Document doc1=new Document();
		Document doc2=new Document();
		//title content image publisher
		//name 域的名称 自定义
		//value  读取的yuan素据的值
		//store 是否进行存储(document的数据输出到索引文件中,并不是所有的元数据内容都需要存储到索引中)
		//YES 表示存储,NO表示不存储
		doc1.add(new TextField("title","国庆大阅兵",Store.YES));
		doc1.add(new TextField("content","10月1日在北京举行的国庆70周年阅兵备受关注",Store.NO));
		doc1.add(new StringField("image", "http://image.jt.com", Store.YES));
		doc1.add(new TextField("publisher", "新华网",Store.YES));
		//价格
		doc1.add(new DoublePoint("price", 500));
		//yes/no 到底什么区别  TextField/StringField/DoublePoint的区别
		doc2.add(new TextField("title","国庆假期准备去哪",Store.YES));
		doc2.add(new TextField("content","10月1日在北京9点开始出城拥堵",Store.YES));
		doc2.add(new TextField("image", "http://image.jt.com/KKK", Store.YES));
		doc2.add(new TextField("publisher", "旅游网",Store.YES));
		//价格
		doc2.add(new DoublePoint("price", 8500));
		//writer携带两个document输出到索引
		writer.addDocument(doc1);
		writer.addDocument(doc2);
		//直接写出
		writer.commit();
	}
	
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package cn.tedu.lucene.index;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.DoublePoint;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.store.FSDirectory;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;


import cn.tedu.lucene.test.IKAnalyzer6x;

/**
 * lucene提供创建倒排索引算法的所有工具
 * 包内容,直接使用工具包实现索引的创建
 * @author 在路上
 *
 */
public class CreateIndex {
/*
 * 1.确定索引的输出位置
 * 2.准备一个具备使用IK分词器输出对象流对象writer
 * 3.内存的document(读取元数据封装)数据封装
 * 4.输出写入到索引文件
 * 域的类型(文本,数字),存储的索引数据
 */
	@Test
	public void createIndex() throws Exception{
		//确认一个输出文件夹位置作为索引
		Path path=Paths.get("d://index01");
		//交给lucene的目录工具类
		FSDirectory dir = FSDirectory.open(path);
		//创建输出对象对应的配置对象
		IndexWriterConfig config=new IndexWriterConfig(new IKAnalyzer6x());
		//定义写出时的方式APPEND  CREATE  CREATE_OR_APPEND
		config.setOpenMode(OpenMode.CREATE);
		//配合dir路径创建输出write
		IndexWriter writer=new IndexWriter(dir, config);
		//封装document  2各document
		Document doc1=new Document();
		Document doc2=new Document();
		//title content image publisher
		//name 域的名称 自定义
		//value  读取的yuan素据的值
		//store 是否进行存储(document的数据输出到索引文件中,并不是所有的元数据内容都需要存储到索引中)
		//YES 表示存储,NO表示不存储
		doc1.add(new TextField("title","国庆大阅兵",Store.YES));
		doc1.add(new TextField("content","10月1日在北京举行的国庆70周年阅兵备受关注",Store.NO));
		doc1.add(new StringField("image", "http://image.jt.com", Store.YES));
		doc1.add(new TextField("publisher", "新华网",Store.YES));
		//价格
		doc1.add(new DoublePoint("price", 500));
		doc1.add(new StringField("price", "500元", Store.YES));
		//yes/no 到底什么区别  TextField/StringField/DoublePoint的区别
		doc2.add(new TextField("title","国庆假期准备去哪",Store.YES));
		doc2.add(new TextField("content","10月1日在北京9点开始出城拥堵",Store.YES));
		doc2.add(new TextField("image", "http://image.jt.com/KKK", Store.YES));
		doc2.add(new TextField("publisher", "旅游网",Store.YES));
		//价格
		doc2.add(new DoublePoint("price", 8500));
		//writer携带两个document输出到索引
		writer.addDocument(doc1);
		writer.addDocument(doc2);
		//直接写出
		writer.commit();
	}
	
}

/*
	 * lucene中将查询功能封装到一个规范(接口类)Query
	 * 可以根据不同的查询功能使用不同的实现类
	 * 
	 * 1.指定查询的索引
	 * 2.搜索对象的创建,使用一个输入流reader
	 * 3.封装查询条件Query,不同的功能,不同的实现类
	 * 4.浅查询实现数据的遍历使用
	 */
	//词项查询
	@Test
	public void termQuery() throws Exception{
		//指定索引位置
		Path path=Paths.get("d://index01");
		FSDirectory dir=FSDirectory.open(path);
		//获取输入流
		IndexReader reader=DirectoryReader.open(dir);
		//利用输入流获取搜索对象
		IndexSearcher search=new IndexSearcher(reader);
		//根据不同的查询条件,封装query实现类对象
		//termquery
		//先提供一个词项 fid域名,关键字条件
		Term term=new Term("title", "国庆");
		Query query=new TermQuery(term);
		//利用浅查询  获取结果集
		TopDocs topDocs=search.search(query, 10);//查询前10条
		//返回的是一个封装搜索计算的浅查询,和对应的document数据
		//评分的对象
		System.out.println("总查询条数:"+topDocs.totalHits);
		System.out.println("其中的最大评分:"+topDocs.getMaxScore());
		ScoreDoc[] docs=topDocs.scoreDocs;//查询的条数10,最多才封装10条
		for (ScoreDoc scoreDoc : docs) {
			//获取document的id值
			System.out.println("document的id值:"+scoreDoc.doc);
			//读取document
			Document doc=search.doc(scoreDoc.doc);
			//读取域属性
			System.out.println("title:"+doc.get("title"));
			System.out.println("content:"+doc.get("content"));
			System.out.println("price:"+doc.get("price"));
			System.out.println("publisher:"+doc.get("publisher"));
			System.out.println("image:"+doc.get("image"));
			
		}
		
		
	}

在这里插入图片描述

//多域查询
	@Test
	public void multiFieldQuery() throws Exception{
		// 指定索引位置
		Path path = Paths.get("d://index01");
		FSDirectory dir = FSDirectory.open(path);
		// 获取输入流
		IndexReader reader = DirectoryReader.open(dir);
		// 利用输入流获取搜索对象
		IndexSearcher search = new IndexSearcher(reader);
		
		//多域查询
		//指定多个域
		String[] fields={"title","content"};
		//封装查询字符串条件 ,利用多域查询的解析器,对条件先进行分词计算
		MultiFieldQueryParser parser=new MultiFieldQueryParser(fields, new IKAnalyzer6x());
		Query query=parser.parse("北京国庆大阅兵");
		//底层封装多个TermQuery   title北京   title国庆  title大  title阅兵
		
		
		// 利用浅查询 获取结果集
		TopDocs topDocs = search.search(query, 10);// 查询前10条
		// 返回的是一个封装搜索计算的浅查询,和对应的document数据
		// 评分的对象,通过topDocs获取封装了documentid的评分数组
		
		
		ScoreDoc[] docs = topDocs.scoreDocs;// 查询的条数10,最多才封装10条
		System.out.println("总查询条数:" + topDocs.totalHits);
		System.out.println("其中的最大评分:" + topDocs.getMaxScore());
		for (ScoreDoc scoreDoc : docs) {
			// 获取document的id值
			System.out.println("document的id值:" + scoreDoc.doc);
			System.out.println("当前document的评分:" + scoreDoc.score);
			// 读取document
			Document doc = search.doc(scoreDoc.doc);
			// 读取域属性
			System.out.println("title:" + doc.get("title"));
			System.out.println("content:" + doc.get("content"));
			System.out.println("price:" + doc.get("price"));
			System.out.println("publisher:" + doc.get("publisher"));
			System.out.println("image:" + doc.get("image"));

		}
	}

在这里插入图片描述

//布尔查询条件
	@Test
	public void booleanQuery() throws Exception{
		// 指定索引位置
		Path path = Paths.get("d://index01");
		FSDirectory dir = FSDirectory.open(path);
		// 获取输入流
		IndexReader reader = DirectoryReader.open(dir);
		// 利用输入流获取搜索对象
		IndexSearcher search = new IndexSearcher(reader);

		//布尔查询
		//封装使用两个子条件
		Query query1=new TermQuery(new Term("title","国庆"));
		Query query2=new TermQuery(new Term("content","周年"));
		//封装布尔子条件
		//query 封装单独的查询条件
		//occur 决定这个条件的逻辑值 MUST  MUST_NOT  filter  should
		//should 与must一起使用无效
		//两个should就是并集
		//filter  效果与must相同,但是无评分===0
		//should和must无效  和filter也无效
		BooleanClause bc1=new BooleanClause(query1, Occur.MUST);
		BooleanClause bc2=new BooleanClause(query2, Occur.MUST_NOT);
		//利用子条件bc1 bc2创建布尔条件
		Query query=new BooleanQuery.Builder().add(bc1).add(bc2).build();
		
		
		// 底层封装多个TermQuery title北京 title国庆 title大 title阅兵

		// 利用浅查询 获取结果集
		TopDocs topDocs = search.search(query, 10);// 查询前10条
		// 返回的是一个封装搜索计算的浅查询,和对应的document数据
		// 评分的对象,通过topDocs获取封装了documentid的评分数组

		ScoreDoc[] docs = topDocs.scoreDocs;// 查询的条数10,最多才封装10条
		System.out.println("总查询条数:" + topDocs.totalHits);
		System.out.println("其中的最大评分:" + topDocs.getMaxScore());
		for (ScoreDoc scoreDoc : docs) {
			// 获取document的id值
			System.out.println("document的id值:" + scoreDoc.doc);
			System.out.println("当前document的评分:" + scoreDoc.score);
			// 读取document
			Document doc = search.doc(scoreDoc.doc);
			// 读取域属性
			System.out.println("title:" + doc.get("title"));
			System.out.println("content:" + doc.get("content"));
			System.out.println("price:" + doc.get("price"));
			System.out.println("publisher:" + doc.get("publisher"));
			System.out.println("image:" + doc.get("image"));

		}
	}

子条件不能过多,2-5之间,过多的子条件会产生复杂的逻辑关系,更不建议多级布尔条件

在这里插入图片描述

//范围查询
	@Test
	public void rangeQuery() throws Exception{
		// 指定索引位置
				Path path = Paths.get("d://index01");
				FSDirectory dir = FSDirectory.open(path);
				// 获取输入流
				IndexReader reader = DirectoryReader.open(dir);
				// 利用输入流获取搜索对象
				IndexSearcher search = new IndexSearcher(reader);

				//范围查询
				Query query=DoublePoint.newRangeQuery("price", 100, 1000);
				
				// 底层封装多个TermQuery title北京 title国庆 title大 title阅兵

				// 利用浅查询 获取结果集
				TopDocs topDocs = search.search(query, 10);// 查询前10条
				// 返回的是一个封装搜索计算的浅查询,和对应的document数据
				// 评分的对象,通过topDocs获取封装了documentid的评分数组

				ScoreDoc[] docs = topDocs.scoreDocs;// 查询的条数10,最多才封装10条
				System.out.println("总查询条数:" + topDocs.totalHits);
				System.out.println("其中的最大评分:" + topDocs.getMaxScore());
				for (ScoreDoc scoreDoc : docs) {
					// 获取document的id值
					System.out.println("document的id值:" + scoreDoc.doc);
					System.out.println("当前document的评分:" + scoreDoc.score);
					// 读取document
					Document doc = search.doc(scoreDoc.doc);
					// 读取域属性
					System.out.println("title:" + doc.get("title"));
					System.out.println("content:" + doc.get("content"));
					System.out.println("price:" + doc.get("price"));
					System.out.println("publisher:" + doc.get("publisher"));
					System.out.println("image:" + doc.get("image"));

				}
	}

在这里插入图片描述
在这里插入图片描述

1.lucene的缺点
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值