lucene

Lucene

  是apache下的一个开源的全文检索引擎工具包(类库)。它的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能。

  它只是一个工具包,并不是一个完整的搜索引擎

全文检索

  全文检索首先将要查询的目标文档中的词提取出来,组成索引,通过查询索引达到搜索目标文档的目的。这种先建立索引,再对索引进行搜索的过程就叫全文检索(Full-text Search

lucene全文检索流程

全文检索要搜索的数据信息格式是多种多样的,比如:搜索引擎(百度, google),通过搜索引擎网站能搜索互联网上的网页(html)、互联网上的音乐(mp3..)、视频(avi..)、pdf电子书等。

全文检索搜索的这些数据称为非结构化数据。

结构化数据:指具有固定格式或有限长度的数据,如数据库,元数据等。

非结构化数据:指不定长或无固定格式的数据,如邮件,word文档等。

如何对结构化数据搜索?

由于结构化数据是固定格式,所以就可以针对固定格式的数据设计算法来搜索,比如数据库like查询,like查询采用顺序扫描法,使用关键字匹配内容,对于内容量大的like查询速度慢。

如何对非结构化数据搜索?

需要将所有要搜索的非结构化数据通过技术手段采集到一个固定的地方,将这些非结构化的数据想办法组成结构化的数据,再以一定的算法去搜索。

由于数据源头是多种多样的,所以:需要将各种各样的数据按照一定的规则统一封装到lucene的文档对象中。有统一的规则,才能进行数据的存储,搜索。

采集数据的过程:就是将数据按照规则封装到lucene文档对象中的过程。

例如:数据库数据的采集

pojo类

package com.lucene.pojo;

public class Book {
    // 图书ID
    private Integer id;
    // 图书名称
    private String name;
    // 图书价格
    private Float price;
    // 图书图片
    private String pic;
    // 图书描述
    private String description;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Float getPrice() {
        return price;
    }
    public void setPrice(Float price) {
        this.price = price;
    }
    public String getPic() {
        return pic;
    }
    public void setPic(String pic) {
        this.pic = pic;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

}

dao接口代码

package com.lucene.dao;

import java.util.List;

import com.lucene.pojo.Book;

public interface BookDao {
    public List<Book> queryBookList();
}

dao实现类

package com.lucene.dao.impl;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.lucene.dao.BookDao;
import com.lucene.pojo.Book;

public class BookDaoImpl implements BookDao {

    @Override
    public List<Book> queryBookList() {
        // 数据库链接
        Connection connection = null;

        // 预编译statement
        PreparedStatement preparedStatement = null;

        // 结果集
        ResultSet resultSet = null;

        // 图书列表
        List<Book> list = new ArrayList<Book>();

        try {
            // 加载数据库驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 连接数据库
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123");

            // SQL语句
            String sql = "SELECT * FROM book";
            // 创建preparedStatement
            preparedStatement = connection.prepareStatement(sql);

            // 获取结果集
            resultSet = preparedStatement.executeQuery();

            // 结果集解析
            while (resultSet.next()) {
                Book book = new Book();
                book.setId(resultSet.getInt("id"));
                book.setName(resultSet.getString("name"));
                book.setPrice(resultSet.getFloat("price"));
                book.setPic(resultSet.getString("pic"));
                book.setDescription(resultSet.getString("description"));
                list.add(book);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (preparedStatement != null) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

        return list;
    }

}

数据库采集,构建索引

IndexWriter是索引过程的核心组件,通过IndexWriter可以创建新索引、更新索引、删除索引操作。IndexWriter需要通过Directory对索引进行存储操作。

Directory描述了索引的存储位置,底层封装了I/O操作,负责对索引进行存储。它是一个抽象类,它的子类常用的包括FSDirectory(在文件系统存储索引)、RAMDirectory(在内存存储索引)。

采集数据的目的是为了索引,在索引前需要将原始内容创建成文档(Document),文档(Document)中包括一个一个的域(Field)。

Tokenizer是分词器,负责将reader转换为语汇单元即进行分词,Lucene提供了很多的分词器,也可以使用第三方的分词,比如IKAnalyzer一个中文分词器。

tokenFilter是分词过滤器,负责对语汇单元进行过滤,tokenFilter可以是一个过滤器链,Lucene提供了很多的分词器过滤器,比如大小写转换、去除停用词等。

如下图是语汇单元的生成过程:

从一个Reader字符流开始,创建一个基于Reader的Tokenizer分词器,经过三个TokenFilter生成语汇单元Token。

Token就是分词过程中产生的对象(包含分词的词语内容,该词在文本中的开始和结束位置)。

term 是搜索时的最小单元。

索引时使用:

输入关键字进行搜索,当需要让该关键字与文档域内容所包含的词进行匹配时需要对文档域内容进行分析,需要经过Analyzer分词器处理生成语汇单元(Token)

搜索时使用:

对搜索关键字进行分析和索引分析一样,使用Analyzer对搜索关键字进行分析、分词处理,使用分析后每个词语进行搜索,匹配。

 /**
     * 收集数据,创建索引
     */
    @Test
    public void test() throws IOException {
        IndexWriter indexWriter = null;
        try {
            //采集数据
            BookDao dao = new BookDaoImpl();
            List<Book> books = dao.queryBookList();
            //将采集的数据放到document对象中
            Document document = null;
            List<Document> documentList = new ArrayList<Document>();
            for (Book book : books) {
                document = new Document();
                //id,不分词,要索引,要存储
                StringField fieldId = new StringField("id", book.getId().toString(), Field.Store.YES);
                //name 要分词,要索引,要存储
                TextField fieldName = new TextField("name", book.getName(), Field.Store.YES);
                //price 是数字比较特殊,要分词(这个不能用textFiled),要索引,要保存
                FloatField priceFiled = new FloatField("price", book.getPrice(), Field.Store.YES);

                //pic 图片的保存路径,不分词,不索引,要保存
                StoredField storedField = new StoredField("pic", book.getPic());

                //description  作者,要分词,要索引,要保存
                TextField descriptionField = new TextField("description", book.getDescription(), Field.Store.YES);
                // /将field对象添加到文档对象中
                document.add(fieldId);
                document.add(fieldName);
                document.add(priceFiled);
                document.add(storedField);
                document.add(descriptionField);
                documentList.add(document);
            }
            //创建一个indexWriter 反向推理出需要的条件,就是通过分词器分词以后,然后去掉停用词,产生的term就是条件
            //例如  如:id: 1, name :java 编程思想
            // 经过分词后得到的term总共有 6个 就是 1. id的term: id :1
            //2.name的term有5个:  name:java   name:编   name:程 name:思 name:想
            //那么就有7个条件能查询到这个document(这个数据)id为1,或者name为 java|编|程|思|想

            //先创建一个directory指定索引库的位置,一般使用文件存储系统存储的位置
            FSDirectory directory = FSDirectory.open(new File("E:\\upload\\lucene"));

            //创建一个分词器,对field进行分词,StandardAnaLyzer是标准的分词器,按英文分词,中午 每个字分
//           Analyzer analyzer = new StandardAnalyzer();
            Analyzer analyzer = new IKAnalyzer();
            IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, analyzer);
            indexWriter = new IndexWriter(directory, config);

            //创建索引
            for (Document d : documentList) {
                indexWriter.addDocument(d);
            }
        }finally {
            if (indexWriter != null) {
                indexWriter.close();
            }
        }
    }

1、用户定义查询语句,用户确定查询什么内容(输入什么关键字)

2、IndexSearcher索引搜索对象,定义了很多搜索方法,程序员调用此方法搜索。

3、IndexReader索引读取对象,它对应的索引维护对象IndexWriter,IndexSearcher通过IndexReader读取索引目录中的索引文件

4、Directory索引流对象,IndexReader需要Directory读取索引库,使用FSDirectory文件系统流对象

5、IndexSearcher搜索完成,返回一个TopDocs(匹配度高的前边的一些记录)

输入查询语句

用户输入查询关键字,执行搜索之前需要先构建一个查询对象,查询对象中可以指定查询要搜索的Field文档域、查询关键字等,查询对象会生成具体的查询语法,

例如:语法 “name:lucene”表示要搜索Field域为name内容为“lucene”的文档

执行查询

通过倒排索引的方式进行查询文档。(

传统方法是先找到文件,再找内容,如何在文件中找内容,在文件内容中匹配搜索关键字,这种方法是顺序扫描方法,数据量大就搜索慢。

倒排索引结构是根据内容(词语)找文档,倒排索引结构也叫反向索引结构,包括索引和文档两部分,索引即词汇表,它是在索引中匹配搜索关键字,由于索引内容量有限并且采用固定优化算法搜索速度很快,找到了索引中的词汇,词汇与文档关联,从而最终找到了文档。

比如:name:lucene    表示要从name域中查询lucene的文档,如下图查询出文档的ID列表。

将查询的结果集进行处理,并渲染到页面,提供给用户一个友好的界面。

搜索查询过程:

第一步:创建一个Directory对象,也就是索引库存放的位置。

第二步:创建一个indexReader对象,需要指定Directory对象。

第三步:创建一个indexsearcher对象,需要指定IndexReader对象

第四步:创建一个TermQuery对象,指定查询的域和查询的关键词。

第五步:执行查询。

第六步:返回查询结果。遍历查询结果并输出。

第七步:关闭IndexReader对象

@Test
    public void doInsearch() throws IOException {
        //指定索引库
        FSDirectory directory = FSDirectory.open(new File("E:\\upload\\lucene"));
        DirectoryReader reader = IndexReader.open(directory);
        //创建indexsearcher对象
        IndexSearcher searcher = new IndexSearcher(reader);
        //创建termquery对象
        TermQuery termQuery = new TermQuery(new Term("description","项目"));
        //构造中传termQuery对象 ,10表示查询分数最高的10条
        TopDocs topdoc = searcher.search(termQuery, 10);

        ScoreDoc[] scoreDocs = topdoc.scoreDocs;

        for (ScoreDoc scoreDoc : scoreDocs) {
            int id = scoreDoc.doc;//文档的id
            Document doc = searcher.doc(id);//获取doc对象

            System.out.println(doc.get("id"));
            System.out.println(doc.get("name"));
            System.out.println(doc.get("price"));
            System.out.println(doc.get("pic"));
            System.out.print(doc.get("description"));
        }
    }

1.1 Field属性

Field是文档中的域,包括Field名和Field值两部分,一个文档可以包括多个Field,Document只是Field的一个承载体,Field值即为要索引的内容,也是要搜索的内容。

是否分词(tokenized),是将field的内容分成一个一个单词。分词的目的:分词目的为了索引,要分词:如: 商品的名称,商品的介绍。不分词,将内容作为一个整体存储。如:商品ID 身份证号,图片路径

l 索引(indexed)   将field的值建立索引,索引的目的:索引的目的为了搜索。建立索引:如:商品的名称,商品的介绍;不建立索引如:图片路径

是否存储(stored)存储的目的:(为了展示在页面) 要存储:如:商品名称,图片路径;不存储:如页面不需要展示的介绍,如果需要展示,根据ID从数据库查询展示在详情页面。

常用的几个用的Filed类型,注意Field的属性,根据需求选择:

索引的更新和删除操作

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.Term;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;

import java.io.File;
import java.io.IOException;

/**
 * Created by Administrator on 2017/8/5.
 */
public class IndexCURD {

    private IndexWriter getIndexWriter() throws IOException {
        //获取索引库
        FSDirectory directory = FSDirectory.open(new File("E:\\upload\\lucene"));
        //创建分词器标准
//        Analyzer analyzer = new StandardAnalyzer();
        //创建ik分词器
        Analyzer analyzer = new IKAnalyzer();
        //创建indexWriterConfig
        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LATEST,analyzer);

        //创建indexWriter
        return new IndexWriter(directory, indexWriterConfig);
    }

    //删除全部索引
    @Test
    public void deleteIndex() throws IOException {
        IndexWriter indexWriter=null;
        try {
            //创建indexWriter
            indexWriter = getIndexWriter();
            //删除指定索引
            indexWriter.deleteDocuments(new Term("name","java"));
        }finally {
            if (indexWriter!=null){
                indexWriter.close();
            }
        }
    }

    //删除索引
    @Test
    public void deleteIndexAll() throws IOException {
        IndexWriter indexWriter=null;
        try {
            //创建indexWriter
            indexWriter =getIndexWriter();
            //删除指定索引
            indexWriter.deleteAll();
        }finally {
            if (indexWriter!=null){
                indexWriter.close();
            }
        }
    }

    //修改索引
    @Test
    public void updateIndex() throws IOException {
        IndexWriter indexWriter = getIndexWriter();

        Document document=new Document();
        IndexableField  i=new TextField("name","apa", Field.Store.YES);
        document.add(i);
        indexWriter.updateDocument(new Term("name","apache"),document);
    }

}
时间: 2024-08-04 04:01:45

lucene的相关文章

lucene中Field.Index,Field.Store的一些设置

lucene在doc.add(new Field("content",curArt.getContent(),Field.Store.NO,Field.Index.TOKENIZED)); Field有两个属性可选:存储和索引. 通过存储属性你可以控制是否对这个Field进行存储: 通过索引属性你可以控制是否对该Field进行索引. 事实上对这两个属性的正确组合很重要. Field.Index Field.Store 说明 TOKENIZED(分词) YES 被分词索引且存储 TOKE

Lucene 基础理论

1. 全文检索系统与Lucene简介 1.1 什么是全文检索与全文检索系统 全文检索是指计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式.这个过程类似于通过字典中的检索字表查字的过程. 全文检索的方法主要分为按字检索和按词检索两种.按字检索是指对于文章中的每一个字都建立索引,检索时将词分解为字的组合.对于各种不同的语言而言,字有不同的含义,比如英文中字与词实际上

一步一步跟我学习lucene(19)---lucene增量更新和NRT(near-real-time)Query近实时查询

这两天加班,不能兼顾博客的更新,请大家见谅. 有时候我们创建完索引之后,数据源可能有更新的内容,而我们又想像数据库那样能直接体现在查询中,这里就是我们所说的增量索引.对于这样的需求我们怎么来实现呢?lucene内部是没有提供这种增量索引的实现的: 这里我们一般可能会想到,将之前的索引全部删除,然后进行索引的重建.对于这种做法,如果数据源的条数不是特别大的情况下倒还可以,如果数据源的条数特别大的话,势必会造成查询数据耗时,同时索引的构建也是比较耗时的,几相叠加,势必可能造成查询的时候数据缺失的情况

一步一步跟我学习lucene(9)---lucene搜索之拼写检查和相似度查询提示(spellcheck)

suggest应用场景 用户的输入行为是不确定的,而我们在写程序的时候总是想让用户按照指定的内容或指定格式的内容进行搜索,这里就要进行人工干预用户输入的搜索条件了:我们在用百度谷歌等搜索引擎的时候经常会看到按键放下的时候直接会提示用户是否想搜索某些相关的内容,恰好lucene在开发的时候想到了这一点,lucene提供的suggest包正是用来解决上述问题的. suggest包联想词相关介绍 suggest包提供了lucene的自动补全或者拼写检查的支持: 拼写检查相关的类在org.apache.

Lucene的一个简单的标准测试(Lucene包基于3.5版本的)

Lucene编程一般分为:索引.分词.搜索 索引源代码: package lucene的一个标准测试; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.Date; import org.apache.lucene.anal

利用Lucene把文本的字体格式进行修改,然后输出到一个新的文件中

这里书中写的是charactorProcess(File file, String destFile) 这里被我改成,(String file,  String destFIle) 一个代表现有的文件和要新建的文件 代码: package com; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.

Lucene基本概念

Lucene基本概念: 1.  Index:索引库,文档的集合组成索引.和一般的数据库不一样,Lucene不支持定义主键,在Lucene中不存在一个叫做Index的类,通过IndexWriter来写索引,通过IndexReader来读索引.索引库在物理形式上一般是位于一个路径下的一系列文件. 2.  分析器:一段有意义的文字需要通过Analyzer分析器分割成一个个词语后才能按关键字搜索,StandardAnalyzer是Lucene中最常用的分析器.为了达到更好的搜索效果,不同的语言可以使用不

lucene分词器中的Analyzer,TokenStream, Tokenizer, TokenFilter

分词器的核心类: Analyzer:分词器 TokenStream: 分词器做好处理之后得到的一个流.这个流中存储了分词的各种信息,可以通过TokenStream有效的获取到分词单元. 以下是把文件流转换成分词流(TokenStream)的过程 首先,通过Tokenizer来进行分词,不同分词器有着不同的Tokenzier,Tokenzier分完词后,通过TokenFilter对已经分好词的数据进行过滤,比如停止词.过滤完之后,把所有的数据组合成一个TokenStream:以下这图就是把一个re

SpringMVC + Mybatis + SpringSecurity(权限控制到方法按钮) + Rest(服务) + Webservice(服务) + Quartz(定时调度)+ Lucene(搜索引擎) + HTML5 bootstrap + Maven项目构建绝对开源平台

框架整合: Springmvc + Mybatis + Shiro(权限) + REST(服务) + WebService(服务) + JMS(消息) + Lucene(搜搜引擎) + Quartz(定时调度) + Bootstrap Html5(支持PC.IOS.Android) 需要源码请加Q:3121026417   此处[源码获取地址] 框架简介: 项目Maven构建,真实大型互联网架构,做到高并发,大数据处理,整个项目使用定制化服务思想,提供模块化.服务化.原子化的方案,将功能模块进行

lucene搜索之高级查询

使用Query子类查询 MatchAllDocsQuery TermQuery NumericRangeQuery BooleanQuery 使用QueryParser QueryParser MulitFieldQueryParser 先抽取公共代码 private void dosearch(Query query) throws IOException { //给出索引库位置 FSDirectory directory = FSDirectory.open(new File("E:\\up