vlambda博客
学习文章列表

Lucene应用实战(一)——索引创建与搜索

Lucene简介

Lucene是非常优秀的成熟的开源的免费的纯java语言的全文索引检索工具包。

Lucene是一个高性能、可伸缩的信息搜索(IR)库。Information Retrieval (IR) library.它可以为你的应用程序添加索引和搜索能力。Lucene是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者 是以此为基础建立起完整的全文检索引擎。由Apache软件基金会支持和提供,Lucene提供了一个简单却强 大的应用程序接口,能够做全文索引和搜索。Lucene是当前以及最近几年非常受欢迎的免费Java信息检索 程序库。

Lucene的实现产品:

Solr : Lucene下的子项目,基于Lucene构建的独立的企业级开源搜索平台,一个服务。它提供了基于 xml/JSON/http的api供外界访问,还有web管理界面。

Elasticsearch:基于Lucene的企业级分布式搜索平台,它对外提供restful-web接口,让程序员可以轻 松、方便使用搜索平台。

特点

稳定、索引性能高 ;

每小时能够索引150GB以上的数据;

对内存的要求小 只需要1MB的堆内存 ;

强大的查询方式支持:短语查询、通配符查询、临近查询、范围查询等 ;

跨平台,Lucene虽然是java编写,但有多种语言实现版可选(如C、C++、Python等),不只是JAVA。

Lucene模块构成

Lucene应用实战(一)——索引创建与搜索

index模块——>主要负责索引的创建,里面有IndexWriter。search模块——>主要负责对索引的搜索。QueryParser——>主要负责语法分析。Document——>相当于一个要进行索引的单元,任何可以想要被索引的文件都必须转化为Document 对象才能进行索引。代表一个虚拟文档与字段,其中字段是可包含在物理文档的内容,元数据等对象。analysis 模块——>主要负责词法分析及语言处理而形成Term。store模块——>主要负责索引的读写。

索引的创建和搜索流程

索引的创建与搜索如下图所示:

Lucene应用实战(一)——索引创建与搜索

索引的创建流程

1.第一步,准备一些要索引的原文档(Document)数据

采集数据分类:1、对于互联网上网页,可以使用工具将网页抓取到本地生成html文件。2、数据库中的数据,可以直接连接数据库读取表中的数据。3、文件系统中的某个文件,可以通过I/O操作读取文件的内容。

1.第二步,创建文档对象——>进行词法分析、语言处理,将原文档传给分词器(Tokenizer) 形成一系列词(Term)

获取原始内容的目的是为了索引,在索引前需要将原始内容创建成文档(Document),文档中包括一 个一个的域(Field),域中存储内容。每个Document可以有多个Field。每个文档都有一个唯一的编号,就是文档id。当然这里传给分词器的操作在addDocument后会自行调用 ,将原始内容创建为包含域(Field)的文档 (document),需要再对域中的内容进行分析,分析成为一个一个的单词(Term)。

1.第三步,索引创建。将得到的词(Term)传给索引组件(Indexer) 形成倒排索引结构

对所有文档分析得出的词汇单元进行索引,索引的目的是为了搜索,最终要实现只搜索被索引的语汇单 元从而找到Document(文档)。

创建索引是对语汇单元索引,通过词语找文档,这种索引的结构叫倒排索引结构。

下面来介绍下倒排索引。

倒排索引结构是根据内容(词汇)找文档,如下图所示:

Lucene应用实战(一)——索引创建与搜索

1.第四步,通过索引存储器将索引写入到磁盘。

索引的搜索流程

索引的搜索流程如下:

1.用户输入查询语句;2.对查询语句经过词法分析和语言分析得到一系列词(Term);3.通过语法分析得到一个查询树;4.通过索引存储将索引读到内存;5.利用查询树搜索索引,从而得到每个词(Term)的文档列表,对文档列表进行交、差、并得到结果文 档;6.将搜索到的结果文档按照对查询语句的相关性进行排序;7.返回查询结果给用户。

代码实战

准备工作

新建maven工程,在pom.xml中添加lucene的相关依赖:

 <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.2</version> </dependency>
<dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-core</artifactId> <version>7.7.3</version> </dependency>
<dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-queryparser</artifactId> <version>7.7.3</version> </dependency>
<dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-analyzers-common</artifactId> <version>7.7.3</version> </dependency>
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>com.github.magese</groupId> <artifactId>ik-analyzer</artifactId> <version>7.7.1</version> </dependency> </dependencies>

创建索引

创建索引,代码如下所示:

 @Test public void testCreateIndex() throws Exception{ //1.采集数据 List<Book> bookList = new ArrayList<>(); Book booka = new Book(); booka.setId(1); booka.setDesc("Lucene Core is a Java library providing powerful indexing and search features, as well as spellchecking, hit highlighting and advanced analysis/tokenization capabilities. The PyLucene sub project provides Python bindings for Lucene Core. "); booka.setName("Lucene"); booka.setPrice(100.45f); bookList.add(booka);
Book bookb = new Book(); bookb.setId(11); bookb.setDesc("Solr is highly scalable, providing fully fault tolerant distributed indexing, search and analytics. It exposes Lucene's features through easy to use JSON/HTTP interfaces or native clients for Java and other languages. "); bookb.setName("Solr"); bookb.setPrice(320.45f); bookList.add(bookb); Book bookc = new Book(); bookc.setId(21); bookc.setDesc("The Apache Hadoop software library is a framework that allows for the distributed processing of large data sets across clusters of computers using simple programming models."); bookc.setName("Hadoop"); bookc.setPrice(620.45f); bookList.add(bookc); //2.创建Document 文档对象 List<Document> documents = new ArrayList<>(); for (Book book:bookList){ Document document = new Document(); // 给document 添加Field document.add(new TextField("id",book.getId().toString(),Field.Store.YES)); document.add(new TextField("name",book.getName(),Field.Store.YES)); document.add(new TextField("price",book.getPrice().toString(),Field.Store.YES)); document.add(new TextField("desc",book.getDesc(),Field.Store.YES)); documents.add(document); }

//3.创建Analyzer 分词器 对文档进行分词 Analyzer analyzer = new StandardAnalyzer(); // 创建Directory 和 IndexWriterConfig 对象 Directory directory = FSDirectory.open(Paths.get("D:/lucene/index")); IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer); // 4.创建IndexWriter 写入对象 IndexWriter indexWriter = new IndexWriter(directory,indexWriterConfig); // 添加文档对象 for (Document doc : documents) { indexWriter.addDocument(doc); } // 释放资源 indexWriter.close(); }

执行完之后在D://lucene//index文件夹中会创建若干文件:

Lucene应用实战(一)——索引创建与搜索

我们如果想要查看这些文件,需要使用一个名叫luke的工具。

具体使用步骤如下:

Lucene应用实战(一)——索引创建与搜索

下载并解压,双击luke.bat打开:

Lucene应用实战(一)——索引创建与搜索

选择要查看的索引的目录:

Lucene应用实战(一)——索引创建与搜索

查看界面可以看到field相关信息:

搜索界面:

搜索时可以使用AND或者OR关键字进行组合查询。注意:此处AND与OR必须大写。

搜索索引

 @Test public void testSearchIndex()throws Exception {
//1.创建Query 搜索对象 // 创建分词器 Analyzer analyzer = new StandardAnalyzer(); // 创建搜索解析器 QueryParser queryParser = new QueryParser("id", analyzer); // 创建搜索对象 Query query = queryParser.parse("desc:java OR name:solr"); //2.创建Directory 流对象 指定索引库位置 //Directory directory = FSDirectory.open(Paths.get("D:/lucene/index")); //Directory directory = SimpleFSDirectory.open(Paths.get("D:/lucene/index")); //Directory directory = NIOFSDirectory.open(Paths.get("D:/lucene/index")); Directory directory = MMapDirectory.open(Paths.get("D:/lucene/index")); //3.创建索引读取对象 IndexReader indexReader = DirectoryReader.open(directory); //4.创建索引搜索对象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); indexSearcher.setSimilarity(new ClassicSimilarity()); System.out.println(indexSearcher.getSimilarity(true)); // indexSearcher.setSimilarity(indexSearcher.getSimilarity(false));
//5.执行搜索 返回结果集 TopDocs TopDocs topDocs = indexSearcher.search(query, 2); System.out.println("查询到的数据总条数:" + topDocs.totalHits); // 获取排序的文档 ScoreDoc[] docs = topDocs.scoreDocs; //6.解析结果集 for (ScoreDoc scoreDoc : docs) { // 获取文档id int docID = scoreDoc.doc; Document doc = indexSearcher.doc(docID); System.out.println("score:" + scoreDoc.score);
System.out.println("docId:" + docID); System.out.println("bookId:" + doc.get("id")); System.out.println("name:" + doc.get("name")); System.out.println("price:" + doc.get("price")); System.out.println("desc:" + doc.get("desc")); System.out.println(); } indexReader.close(); }

执行结果:

ClassicSimilarity查询到的数据总条数:2score:1.9506836docId:1bookId:11name:Solrprice:320.45desc:Solr is highly scalable, providing fully fault tolerant distributed indexing, search and analytics. It exposes Lucene's features through easy to use JSON/HTTP interfaces or native clients for Java and other languages. 
score:0.2575364docId:0bookId:1name:Luceneprice:100.45desc:Lucene Core is a Java library providing powerful indexing and search features, as well as spellchecking, hit highlighting and advanced analysis/tokenization capabilities. The PyLucene sub project provides Python bindings for Lucene Core.

总结

本文对Lucene进行了简单介绍,并对其索引的创建与搜索流程进行了梳理,并有相关的代码实战,并对倒排索引有了初步的了解。

更多