Solr底层Api:Lucene

编程入门 行业动态 更新时间:2024-10-27 19:17:32

Solr<a href=https://www.elefans.com/category/jswz/34/1768082.html style=底层Api:Lucene"/>

Solr底层Api:Lucene

什么是lucene?

logo:

1)Lucene是一套用于全文检索和搜寻的开源程序库,由Apache软件基金会支持和提供
2)Lucene提供了一个简单却强大的应用程序接口(API),能够做全文索引和搜寻,在Java开发环境里Lucene是一个成熟的免费开放源代码工具
3)Lucene并不是现成的搜索引擎产品,但可以用来制作搜索引擎产品

4)官网:/

 

什么是全文检索?

 

lucene和solr的关系

 

实现搜索的方式:

方式1:数据库搜索

利用SQL语句进行模糊搜索:
select * from items where title like “%小米%”;
问题:
数据量很大的情况下,模糊搜索不一定走索引,因此效率就会很低。


方式2:Lucene技术

海量数据的情况下,利用倒排索引技术,实现快速的搜索、打分、排序等功能 

 

倒排索引技术:

 

创建倒排索引,分为以下几步:
1)创建文档列表:

             lucene首先对原始文档数据进行编号(DocID),形成列表,就是一个文档列表

2)创建倒排索引列表:

              然后对文档中数据进行分词,得到词条。对词条进行编号,以词条创建索引。然后记录下包含该词条的所有文档编号(及其它信息)。

江湖悠悠 -->江湖、悠悠

倒排索引创建索引的流程:
1)首先把所有的原始数据进行编号,形成文档列表

2)把文档数据进行分词,得到很多的词条,以词条为索引。保存包含这些词条的文档的编号信息

搜索的过程:
当用户输入任意的词条时,首先对用户输入的数据进行分词,得到用户要搜索的所有词条,然后拿着这些词条去倒排索引列表中进行匹配。找到这些词条就能找到包含这些词条的所有文档的编号。然后根据这些编号去文档列表中找到文档

例如用户在百度中搜索"江湖"关键字,lucene根据这个单词,找到倒排列表中的文档id(0,1) ,然后根据文档id(0,1)查找出"j江湖悠悠,饮一壶浊酒"和“行走江湖,靠的是颜值”这两条数据展示给用户

 

Lucene的基本使用

使用Lucene的API来实现对索引的增(创建索引)、删(删除索引)、改(修改索引)、查(搜索数据)。

一:导入依赖

<dependencies>
<!-- Junit单元测试 -->
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version>
</dependency>
<!-- lucene核心库 -->
<dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-core</artifactId><version>4.10.2</version>
</dependency>
<!-- Lucene的查询解析器 -->
<dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-queryparser</artifactId><version>4.10.2</version>
</dependency>
<!-- lucene的高亮显示 -->
<dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-highlighter</artifactId><version>4.10.2</version>
</dependency>
<!-- IK分词器 -->
<dependency><groupId>com.janeluo</groupId><artifactId>ikanalyzer</artifactId><version>2012_u6</version>
</dependency>
</dependencies>

添加:

package LuceneTest;import java.io.File;
import java.util.ArrayList;
import java.util.List;import org.apache.lucene.document.Document;
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.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;public class LuceneCreate {/** 创建文档(原始数据)索引*/@Testpublic void createIndex() throws Exception {// 创建文档对象Document document = new Document();// 创建并添加字段信息。参数:字段的名称、字段的值、是否存储,这里选Store.YES代表存储到文档列表。Store.NO代表不存储document.add(new StringField("id", "1", Store.YES));// 这里我们title字段需要用TextField,即创建索引又会被分词。StringField会创建索引,但是不会被分词document.add(new TextField("title", "今夜漫长,江湖悠悠,孤饮一杯浊酒", Store.YES));// 索引目录类,保存到项目下indexDir目录Directory directory = FSDirectory.open(new File("indexDir"));// 创建分词器对象IKAnalyzer analyzer = new IKAnalyzer();// 索引写出工具的配置对象IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST, analyzer);// 创建索引的写出工具类。参数:索引的目录和配置信息IndexWriter indexWriter = new IndexWriter(directory, conf);// 把文档交给IndexWriterindexWriter.addDocument(document);// 提交indexWritermit();// 关闭indexWriter.close();}/*** 批量创建文档索引* * @param @throws Exception* @throws*/@Testpublic void createBatchIndex() throws Exception {// 创建文档的集合List<Document> docs = new ArrayList<Document>();// 创建文档对象Document document1 = new Document();document1.add(new StringField("id", "1", Store.YES));document1.add(new TextField("title", "今夜漫长,江湖悠悠,孤饮一杯浊酒", Store.YES));docs.add(document1);// 创建文档对象Document document2 = new Document();document2.add(new StringField("id", "2", Store.YES));document2.add(new TextField("title", "行走江湖,靠的就是颜值", Store.YES));docs.add(document2);// 索引目录类,指定索引在硬盘中的位置Directory directory = FSDirectory.open(new File("indexDir"));// 引入IK分词器IKAnalyzer analyzer = new IKAnalyzer();// 索引写出工具的配置对象IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST, analyzer);// 设置打开方式:OpenMode.APPEND 会在索引库的基础上追加新索引。OpenMode.CREATE会先清空原来数据,再提交新的索引conf.setOpenMode(OpenMode.CREATE);// 创建索引的写出工具类。参数:索引的目录和配置信息IndexWriter indexWriter = new IndexWriter(directory, conf);// 把文档集合交给IndexWriterindexWriter.addDocuments(docs);// 提交indexWritermit();// 关闭indexWriter.close();}
}

修改:

package LuceneTest;import java.io.File;import org.apache.lucene.document.Document;
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.Term;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;public class LuceneUpdate {/** 测试:修改索引 注意: A:Lucene修改功能底层会先删除,再把新的文档添加。* B:修改功能会根据Term进行匹配,所有匹配到的都会被删除。这样不好 C:因此,一般我们修改时,都会根据一个唯一不重复字段进行匹配修改。例如ID* D:但是词条搜索,要求ID必须是字符串。如果不是,这个方法就不能用。* 如果ID是数值类型,我们不能直接去修改。可以先手动删除deleteDocuments(数值范围查询锁定ID),再添加。*/@Testpublic void updateIndex() throws Exception {// 创建目录对象Directory directory = FSDirectory.open(new File("indexDir"));// 创建配置对象IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST,new IKAnalyzer());// 创建索引写出工具IndexWriter writer = new IndexWriter(directory, conf);// 创建新的文档数据Document doc = new Document();doc.add(new StringField("id", "1", Store.YES));doc.add(new TextField("title", "哈哈,追不上我吧,我就是这么强大",Store.YES));/** 修改索引。参数: 词条:根据这个词条匹配到的所有文档都会被修改 文档信息:要修改的新的文档数据*/writer.updateDocument(new Term("id", "1"), doc);// 提交writermit();// 关闭writer.close();}
}

删除:

package LuceneTest;import java.io.File;import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;public class LuceneDelete {/** 演示:删除索引 注意: 一般,为了进行精确删除,我们会根据唯一字段来删除。比如ID 如果是用Term删除,要求ID也必须是字符串类型!*/@Testpublic void deleteIndex() throws Exception {// 创建目录对象Directory directory = FSDirectory.open(new File("indexDir"));// 创建配置对象IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST,new IKAnalyzer());// 创建索引写出工具IndexWriter writer = new IndexWriter(directory, conf);// 根据词条进行删除writer.deleteDocuments(new Term("id", "1"));// 删除所有// writer.deleteAll();// 提交writermit();// 关闭writer.close();}}

查询:

package LuceneTest;import java.io.File;import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.WildcardQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;public class LuceneSearch {public void search(Query query) throws Exception {// 索引目录对象Directory directory = FSDirectory.open(new File("indexDir"));// 索引读取工具IndexReader reader = DirectoryReader.open(directory);// 索引搜索工具IndexSearcher searcher = new IndexSearcher(reader);// 搜索数据,两个参数:查询条件对象要查询的最大结果条数// 返回的结果是 按照匹配度排名得分前N名的文档信息(包含查询到的总条数信息、所有符合条件的文档的编号信息)。TopDocs topDocs = searcher.search(query, 10);// 获取总条数System.out.println("本次搜索共找到" + topDocs.totalHits + "条数据");// 获取得分文档对象(ScoreDoc)数组.SocreDoc中包含:文档的编号、文档的得分ScoreDoc[] scoreDocs = topDocs.scoreDocs;for (ScoreDoc scoreDoc : scoreDocs) {// 取出文档编号int docID = scoreDoc.doc;// 根据编号去找文档Document doc = reader.document(docID);System.out.println("id: " + doc.get("id"));System.out.println("title: " + doc.get("title"));// 取出文档得分System.out.println("得分: " + scoreDoc.score);}}/*** 根据多个字段查询* */@Testpublic void search1() throws Exception {MultiFieldQueryParser parser = new MultiFieldQueryParser(new String[] {"id", "title" }, new IKAnalyzer());//Query query = parser.parse("1");//自动匹配id进行查询Query query = parser.parse("浊酒");//自动匹配title进行查询search(query);}/*** 普通词条查询* */@Testpublic void search2() throws Exception {// 创建词条查询对象Query query = new TermQuery(new Term("title", "浊酒"));search(query);}/*** 模糊查询* 	? 可以代表任意一个字符* 	* 可以任意多个任意字符*/@Testpublic void search3() throws Exception {// 创建查询对象Query query = new WildcardQuery(new Term("title", "*酒*"));search(query);}/*** 测试相似度查询*/@Testpublic void testFuzzyQuery() throws Exception {//如果不采用FuzzyQuery,根据“烈酒”词条是查询不出结果的Query query = new FuzzyQuery(new Term("title","烈酒"));search(query);}}

 

高亮显示关键字:

 

原理:

1)给所有关键字加上一个HTML标签

        

      2)给这个特殊的标签设置CSS样式

       

代码实现:

// 高亮显示@Testpublic void testHighlighter() throws Exception {// 目录对象Directory directory = FSDirectory.open(new File("indexDir"));// 创建读取工具IndexReader reader = DirectoryReader.open(directory);// 创建搜索工具IndexSearcher searcher = new IndexSearcher(reader);QueryParser parser = new QueryParser("title", new IKAnalyzer());Query query = parser.parse("江湖");// 格式化器Formatter formatter = new SimpleHTMLFormatter("<em>", "</em>");Scorer scorer = new QueryScorer(query);// 准备高亮工具Highlighter highlighter = new Highlighter(formatter, scorer);// 搜索TopDocs topDocs = searcher.search(query, 10);System.out.println("本次搜索共" + topDocs.totalHits + "条数据");ScoreDoc[] scoreDocs = topDocs.scoreDocs;for (ScoreDoc scoreDoc : scoreDocs) {// 获取文档编号int docID = scoreDoc.doc;Document doc = reader.document(docID);System.out.println("id: " + doc.get("id"));String title = doc.get("title");// 用高亮工具处理普通的查询结果,参数:分词器,要高亮的字段的名称,高亮字段的原始值String hTitle = highlighter.getBestFragment(new IKAnalyzer(), "title", title);System.out.println("title: " + hTitle);// 获取文档的得分System.out.println("得分:" + scoreDoc.score);}}

 

 

 

更多推荐

Solr底层Api:Lucene

本文发布于:2024-02-08 21:53:33,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1675476.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:底层   Solr   Lucene   Api

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!