搜索学习入门--Lucene初体验(Lucene索引的增删改查)

Lucene是一个开放源代码的全文检索引擎工具包,它提供了完整的查询引擎和索引引擎,开发人员可以方便的在目标系统中实现全文检索。Lucene的核心使用的是基于倒排索引的,并且实现了实现了分块索引。下面,先来体验一下Lucene对索引的增删改查功能。Lucene存储对象是以document为存储单元,对象中相关的属性值则存放到Field中。

第一步:引入依赖

<!-- Lucene核心 -->
<dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-core</artifactId>
    <version>4.7.2</version>
</dependency>

<!-- Lucene搜索查询相关 -->
<dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-queryparser</artifactId>
    <version>4.7.2</version>
</dependency>

<!-- Lucene分词器相关 -->
<dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-analyzers-common</artifactId>
    <version>4.7.2</version>
</dependency>

第二步:建立索引

这里使用标准分词器建立5个Document的索引

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.*;
import org.apache.lucene.index.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;

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

/**
 * created by yuyufeng on 2017/11/13.
 */
public class LuceneIndexDemo {
    public static void main(String[] args) {
        // Lucene Document的域名
        String fieldName = "blog";
        String text = "";
        // 建立5条索引
        text = "10月11日杭州云栖大会上,马云表达了对新建成的阿里巴巴全球研究院—阿里巴巴达摩院的愿景,希望达摩院二十年内成为世界第一大经济体,服务世界二十亿人,创造一亿个工作岗位。";
        doIndex(fieldName, text);
        text = "中国互联网界,阿里巴巴被认为是技术实力最弱的公司。我确实不懂技术,承认不懂技术不丢人,不懂装懂才丢人。";
        doIndex(fieldName, text);
        text = "阿里巴巴未来二十年的目标是打造世界第五大经济体,不是我们狂妄,而是世界需要这么一个经济体,也一定会有这么一个经济体。";
        doIndex(fieldName, text);
        text = "达摩院一定也必须要超越英特尔,必须超越微软,必须超越IBM,因为我们生于二十一世纪,我们是有机会后发优势的。";
        doIndex(fieldName, text);
        text = "阿里巴巴有很多争议,似乎无处不在,我还真想不出有什么东西是我们不做的。互联网是一种思想,是一种技术革命,不应该有界限。跨界乐趣无穷。我觉得阿里巴巴的跨界还不错";
        doIndex(fieldName, text);


    }

    private static void doIndex(String fieldName, String text) {
        // 实例化IKAnalyzer分词器
        Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_47);

        Directory directory = null;
        IndexWriter iwriter;
        try {
            // 索引目录
            directory = new SimpleFSDirectory(new File("D://test/lucene_index"));

            // 配置IndexWriterConfig
            IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_47, analyzer);
            iwConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
            iwriter = new IndexWriter(directory, iwConfig);
            // 写入索引
            Document doc = new Document();
            Long id = System.currentTimeMillis();
            doc.add(new StringField("ID", id+"", Field.Store.YES));
            doc.add(new TextField(fieldName, text, Field.Store.YES));
            iwriter.addDocument(doc);
            iwriter.close();
            System.out.println("建立索引成功:" + id);
        } catch (CorruptIndexException e) {
            e.printStackTrace();
        } catch (LockObtainFailedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (directory != null) {
                try {
                    directory.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

运行结果
建立索引成功:1510579712099
建立索引成功:1510579712355
建立索引成功:1510579712512
建立索引成功:1510579712743
建立索引成功:1510579712912

查看索引文件:运行之后,打开我们存放索引的文件夹,你会看到如下文件列表结构:

这里写图片描述

第三步:搜索查询

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;

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

/**
 * created by yuyufeng on 2017/11/13.
 */
public class LuceneSearchDemo {
    public static void main(String[] args) {

        // Lucene Document的域名
        String fieldName = "blog";
        Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_47);
        Directory directory = null;
        IndexReader ireader = null;
        IndexSearcher isearcher;

        try {
            //索引目录
            directory = new SimpleFSDirectory(new File("D://test/lucene_index"));
            // 配置IndexWriterConfig
            IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_47, analyzer);
            iwConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);

            // 搜索过程**********************************
            // 实例化搜索器
            ireader = DirectoryReader.open(directory);
            isearcher = new IndexSearcher(ireader);

            String keyword = "达摩院";
            // 使用QueryParser查询分析器构造Query对象
            QueryParser qp = new QueryParser(Version.LUCENE_47, fieldName, analyzer);
            qp.setDefaultOperator(QueryParser.OR_OPERATOR);  // and or 跟数据库查询语法类似
            Query query = qp.parse(keyword);
            System.out.println("Query = " + query);

            // 搜索相似度最高的5条记录
            TopDocs topDocs = isearcher.search(query, 5);
            System.out.println("命中:" + topDocs.totalHits);
            // 遍历输出结果
            ScoreDoc[] scoreDocs = topDocs.scoreDocs;
            for (int i = 0; i < topDocs.totalHits; i++) {
                Document targetDoc = isearcher.doc(scoreDocs[i].doc);
                System.out.println("内容:" + targetDoc.toString());
            }
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ireader != null) {
                try {
                    ireader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (directory != null) {
                try {
                    directory.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

**keyword= :"达摩院"
运行结果

Query = blog:达 blog:摩 blog:院
命中:2
内容:Document<<stored<ID:1510579934220> stored,indexed,tokenized<blog:10月11日杭州云栖大会上,马云表达了对新建成的阿里巴巴全球研究院—阿里巴巴达摩院的愿景,希望达摩院二十年内成为世界第一大经济体,服务世界二十亿人,创造一亿个工作岗位。>>
内容:Document<stored<ID:1510579934765> stored,indexed,tokenized<blog:达摩院一定也必须要超越英特尔,必须超越微软,必须超越IBM,因为我们生于二十一世纪,我们是有机会后发优势的。>>    

**keyword= :"阿里巴巴达摩院"
运行结果

Query = blog:阿 blog:里 blog:巴 blog:巴 blog:达 blog:摩 blog:院
命中:5
内容:Document<stored<ID:1510579934220> stored,indexed,tokenized<blog:10月11日杭州云栖大会上,马云表达了对新建成的阿里巴巴全球研究院—阿里巴巴达摩院的愿景,希望达摩院二十年内成为世界第一大经济体,服务世界二十亿人,创造一亿个工作岗位。>>
内容:Document<stored<ID:1510579934932> stored,indexed,tokenized<blog:阿里巴巴有很多争议,似乎无处不在,我还真想不出有什么东西是我们不做的。互联网是一种思想,是一种技术革命,不应该有界限。跨界乐趣无穷。我觉得阿里巴巴的跨界还不错>>
内容:Document<stored<ID:1510579934765> stored,indexed,tokenized<blog:达摩院一定也必须要超越英特尔,必须超越微软,必须超越IBM,因为我们生于二十一世纪,我们是有机会后发优势的。>>
内容:Document<stored<ID:1510579934474> stored,indexed,tokenized<blog:中国互联网界,阿里巴巴被认为是技术实力最弱的公司。我确实不懂技术,承认不懂技术不丢人,不懂装懂才丢人。>>
内容:Document<stored<ID:1510579934606> stored,indexed,tokenized<blog:阿里巴巴未来二十年的目标是打造世界第五大经济体,不是我们狂妄,而是世界需要这么一个经济体,也一定会有这么一个经济体。>>

第四步:更新索引文档

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.*;
import org.apache.lucene.index.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;

public class LuceneUpdateDemo {
    public static void main(String[] args) {
        // 实例化IKAnalyzer分词器
        Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_47);

        Directory directory = null;
        IndexWriter iwriter;
        try {
            // 索引目录
            directory = new SimpleFSDirectory(new File("D://test/lucene_index"));

            // 配置IndexWriterConfig
            IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_47, analyzer);
            iwConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
            iwriter = new IndexWriter(directory, iwConfig);
            // 写入索引
            Document doc = new Document();
            String id = "1510579934220";
            doc.add(new StringField("ID", id, Field.Store.YES));
            doc.add(new TextField("blog", "更新文档后->达摩院一定也必须要超越英特尔,必须超越微软,必须超越IBM,因为我们生于二十一世纪,我们是有机会后发优势的。", Field.Store.YES));
            //先根据Term ID 删除,在建立新的索引
            iwriter.updateDocument(new Term("ID", id), doc);
            iwriter.close();
            System.out.println("更新索引成功:" + 1511233039462L);
        } catch (CorruptIndexException e) {
            e.printStackTrace();
        } catch (LockObtainFailedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (directory != null) {
                try {
                    directory.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

在执行第三步查询,即可查看更新结果

第五步:索引删除

package top.yuyufeng.learn.lucene.demo1;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.*;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;

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

/**
 * @author yuyufeng
 * @date 2017/11/21
 */
public class LuceneDeleteDemo {
    public static void main(String[] args) {
        // Lucene Document的域名
        String fieldName = "blog";
        Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_47);
        Directory directory = null;
        IndexReader ireader = null;
        IndexSearcher isearcher;
        IndexWriter iwriter = null;
        try {
            //索引目录
            directory = new SimpleFSDirectory(new File("D://test/lucene_index"));
            // 配置IndexWriterConfig
            IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_47, analyzer);
            iwConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
            ireader = DirectoryReader.open(directory);
            iwriter = new IndexWriter(directory, iwConfig);
            iwriter.deleteDocuments(new Term("ID","1511235710648"));
            //使用IndexWriter进行Document删除操作时,文档并不会立即被删除,而是把这个删除动作缓存起来,当IndexWriter.Commit()或IndexWriter.Close()时,删除操作才会被真正执行。
            iwriter.commit();
            iwriter.close();
            ireader.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (directory != null) {
                try {
                    directory.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
方法 说明
DeleteDocuments(Query query) 根据Query条件来删除单个或多个Document
DeleteDocuments(Query[] queries) 根据Query条件来删除单个或多个Document
DeleteDocuments(Term term) 根据Term来删除单个或多个Document
DeleteDocuments(Term[] terms) 根据Term来删除单个或多个Document
DeleteAll() 删除所有的Document
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,423评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,147评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,019评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,443评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,535评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,798评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,941评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,704评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,152评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,494评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,629评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,295评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,901评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,978评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,333评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,499评论 2 348

推荐阅读更多精彩内容