Lucene实战

写索引

·获取IndexWriter

public IndexWriter getIndexWriter(String path) throws IOException {
		Directory dir=FSDirectory.open(Paths.get(path));//获取目录对象  索引将写在这个目录里面
		
		Analyzer analyzer=new StandardAnalyzer();//构造分析器实例  这里用到的是标准分词器StandardAnalyzer
		IndexWriterConfig config=new IndexWriterConfig(analyzer);//通过分析器构造IndexWriter的配置对象
		
		return new IndexWriter(dir,config);//通过目录对象与配置对象实例化IndexWriter对象
	}

·添加索引

public void writerIndex() throws IOException {
		IndexWriter writer=this.getIndexWriter("F:\\Lucene5\\index");//获取IndexWriter对象
		for(int i=0;i<4;i++) {
			Document document=new Document();//新建文档对象
			document.add(new StringField("id", String.valueOf(ids[i]), Field.Store.YES));//这个Field域将存储在文件中,可以恢复
			document.add(new StringField("name", String.valueOf(names[i]), Field.Store.YES));//根据你自己的类型选择合适的Field
			document.add(new TextField("dec", String.valueOf(decs[i]), Field.Store.NO));//不存储在文件中,但是可以索引到
			writer.addDocument(document);//一个对象封装在一个document中,这里共四个document
		}
		writer.close();//关闭indexWriter
	}

·索引更新

public void update()throws Exception{
		IndexWriter writer=getWriter();
		Document doc=new Document();//新建文档,写入更新内容
		doc.add(new StringField("id", "1", Field.Store.YES));
		doc.add(new StringField("name","张三",Field.Store.YES));
		doc.add(new TextField("dec", "hahahaha.", Field.Store.NO));
		writer.updateDocument(new Term("id","1"), doc);//更新文档,指定搜索要更新的文档指定域
		writer.close();
	}

·删除索引

public void deleteMerge()throws Exception{
		IndexWriter writer=getIndexWriter();
		System.out.println("删除前:"+writer.numDocs());
		writer.deleteDocuments(new Term("id","1"));
		writer.forceMergeDeletes(); // 马上强制删除,不推荐,因为高并发的情况下浪费了系统资源    
            // writer.deleteDocuments(new Term("id","1"));(推荐,相当于放在了回收站中)标记了删除,没有在文件中删除,索引不到
                writer.commit();writer.close();}

搜索

·获取IndexSearcher对象

public IndexSearcher getIndexSearcher(String path) throws IOException {
		Directory dir=FSDirectory.open(Paths.get(path));//通过要检索的目录实例化目录对象
		IndexReader indexReader=DirectoryReader.open(dir);//通过目录对象实例化indexReader
		return new IndexSearcher(indexReader);//创建并返回IndexSearcher实例
	}

·索引库查询

1、对要搜索的信息创建Query查询对象,Lucene会更具Query对象生成最终的查询语法。

2、两种方式创建Query对象,有了该对象,就可以使用IndexSearcher进行检索了。

使用QueryParse查询剖析器解析查询表达式要加入lucene-queryparser jar包

public void testQueryParseSearch(String q) throws IOException, ParseException {
		//获取searcher对象,该对象作用在于已建立好的索引上进行检索
		IndexSearcher indexSearcher=this.getIndexSearcher("F:\\Lucene5\\index");		
		
		Analyzer analyzer=new StandardAnalyzer(); // 标准分词器  
		QueryParser queryParser=new QueryParser("des", analyzer);//查询剖析器。指定对那个域进行检索,并选择分词器
		Query query=queryParser.parse(q);//Query 是lucene能识别的查询,q是传进来的查询字段
		
		TopDocs hits=indexSearcher.search(query, 100);//搜索返回前100条记录,简单的指针容器
		for(ScoreDoc scoreDoc:hits.scoreDocs){        //得分文档,查到的文档
			Document doc=indexSearcher.doc(scoreDoc.doc);    //打开文档
			doc.get("name");//获取字段
		}
		
	}

·使用Lucene提供的Query子类,如TermRangeQuery、NumericRangeQuery、PrefixQuery、BooleanQuery

指定字符串开头搜索

public void testPrefixQuery()throws Exception{                          //Term  搜索功能的基本单元
		PrefixQuery query=new PrefixQuery(new Term("city","a"));//(指定域,指定开头字符)
		TopDocs hits=is.search(query, 10);
		for(ScoreDoc scoreDoc:hits.scoreDocs){
			Document doc=is.doc(scoreDoc.doc);
			System.out.println(doc.get("id"));
		}	
	}

指定数字范围搜索

public void testNumericRangeQuery()throws Exception{
		NumericRangeQuery<Integer> query=NumericRangeQuery.newIntRange("id", 1, 2, true, true);1~2范围
		TopDocs hits=is.search(query, 10);
		for(ScoreDoc scoreDoc:hits.scoreDocs){
			Document doc=is.doc(scoreDoc.doc);
			System.out.println(doc.get("name"));
		}		
	}

多条件查询

public void testBooleanQuery()throws Exception{
		NumericRangeQuery<Integer> query1=NumericRangeQuery.newIntRange("id", 1, 2, true, true);
		PrefixQuery query2=new PrefixQuery(new Term("city","a"));
		BooleanQuery.Builder booleanQuery=new BooleanQuery.Builder();
		booleanQuery.add(query1,BooleanClause.Occur.MUST);
		booleanQuery.add(query2,BooleanClause.Occur.MUST);
		TopDocs hits=is.search(booleanQuery.build(), 10);
		for(ScoreDoc scoreDoc:hits.scoreDocs){
			Document doc=is.doc(scoreDoc.doc);
			System.out.println(doc.get("name"));
		}	
	}

中文分词

  • StandardAnalyzer 
    单字分词,就是按照中文一个字一个字地进行分词。如:“我爱中国”,效果:“我”、“爱”、“中”、“国”。
  • CJKAnalyzer 
    二分法分词,按两个字进行切分。如:“我是中国人”,效果:“我是”、“是中”、“中国”、“国人”。 
    上边这两个分词器一看就无法满足需求。
  • SmartChineseAnalyzer (中科院搞的,要添加这个jar包)
    对中文支持较好,但扩展性差,扩展词库,禁用词库和同义词库等不好处理。

高亮

//此处加入的是搜索结果的高亮部分
    SimpleHTMLFormatter simpleHTMLFormatter = new SimpleHTMLFormatter("<b><font color=red>","</font></b>"); //如果不指定参数的话,默认是加粗,即<b><b/>
    QueryScorer scorer = new QueryScorer(query);//计算得分,会初始化一个查询结果最高的得分
    Fragmenter fragmenter = new SimpleSpanFragmenter(scorer); //根据这个得分计算出一个片段
    Highlighter highlighter = new Highlighter(simpleHTMLFormatter, scorer);//高亮,挑选出一个合适的
    highlighter.setTextFragmenter(fragmenter); //设置一下要显示的片段
    for(ScoreDoc scoreDoc : docs.scoreDocs) { //取出每条查询结果
        Document doc = searcher.doc(scoreDoc.doc); //scoreDoc.doc相当于docID,根据这个docID来获取文档
        System.out.println(doc.get("city")); 
        System.out.println(doc.get("desc")); 
        String desc = doc.get("desc");
      //显示高亮部分
        if(desc != null) {
            TokenStream tokenStream = analyzer.tokenStream("desc", new StringReader(desc));//找到原始文本
            String summary = highlighter.getBestFragment(tokenStream, desc);
            System.out.println(summary);
        }

最后

·Field.Index和Field.Store

        //Field.Store.YES或者NO部分
        // 如果为YES,代表着是否要把这个域中的内容完全存储到文件中,方便进行还原
        //如果为NO,代表着不把这个域的内容存储到文件,但是可以被索引,但是这些内容不可被还原
        //Field.Index.ANALYZED:进行分词和索引,适用于标题,内容等
        //Field.Index.NOT_ANALYZED:进行索引,但是不进行分词。精准的数据不分词,像id,身份证号,姓名等不分词,用于精确搜索
        //Field.Index.ANALYZED_NOT_NORMS:进行分词但是不存储norm信息,这个norms中包括了索引的时间和权值等信息
        //Field.Index.NOT_ANALYZED_NOT_NORMS:既不进行分词,也不存储norms信息
        /Field.Index.NO:完全不进行索引

·IndexReader顾名思义,它是用来读取索引的信息的,下面来演示一些它的用法

(1)获取文档的数量

//存储的文档数量,也就是document对象的数量,删除索引后,这个数值会减少
System.out.println("存储的文档数量: " + reader.numDocs());

(2)获取文档的总量

//存储过的文档的最大数量,删除索引后,数量不会减少
//此时删除的文件并不会完全删除,它存在回收站里面
System.out.println("文档存储的总存储量: " + reader.maxDoc());

 (3)获取已删除文档的数量

System.out.println("删除文档的数量: " + reader.numDeletedDocs());

·

 writer.deleteDocuments(new Term("id","1"));
注意,这里的删除,并不是真的删除。执行完之后,可以在索引的目录里面看到多了一个.del的文件,那是一个类似回收站的文件,在回收站中的文件是可以进行还原的

 public void recovery(){
        try {
            //这一步很重要,因为默认打开的reader是只读的,所以这里要通过构造方法,把它的readonly设置为false,否则会抛出异常
            IndexReader reader = IndexReader.open(directory,false);
            //还原所有已删除的数据
            reader.undeleteAll();

            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


PS:后面很乱 借鉴了   https://www.cnblogs.com/zhuxiaojie/p/5277219.html#autoid-1-0-0


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值