关于主分片以及副本数量设定

回复

Elasticsearch匿名用户 回复了问题 • 1 人关注 • 1 个回复 • 2234 次浏览 • 2016-06-25 19:27 • 来自相关话题

es删除一个集群的某一节点

Elasticsearchflowaters 回复了问题 • 2 人关注 • 1 个回复 • 2698 次浏览 • 2016-06-25 19:23 • 来自相关话题

MapperParsingException[Failed to parse mapping [_default_]:

ElasticsearchJay 回复了问题 • 3 人关注 • 4 个回复 • 2791 次浏览 • 2016-06-24 16:08 • 来自相关话题

Lucene5.5入门第十篇完结篇——使用Highlighter使关键词高亮

Lucenekl 发表了文章 • 0 个评论 • 2672 次浏览 • 2016-06-24 11:27 • 来自相关话题

前言

我们在使用百度和谷歌等搜索引擎的时候,你会发现,搜索引擎会把和我们输入的关键字以红色的字体显示,来突出显示结果的准确性,这就是高亮显示的使用场景

准备

使用Highlighter需要导入相应的jar包,maven项目可以加入如下依赖

<dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-highlighter</artifactId>
            <version>5.5.0</version>
   </dependency>

直接看代码


/**
 * @author kl by 2016/3/19
 * @boke www.kailing.pub
 */
public class FieldSetBoostTest {
    //索引目录
    String indexDir="E:\\LuceneIndex";
    //测试数据
    String theme="中国";
    String []title={"中国是一个伟大的国家","我爱你的的祖国,美丽的中国","是什么,中国令美日等国虎视眈眈"};
    /**
     * Lucence5.5返回IndexWriter实例
     * @param directory
     * @return
     */
    public IndexWriter getIndexWriter(Directory directory){
        Analyzer analyzer=new CJKAnalyzer();//中日韩二元分词
        IndexWriterConfig writerConfig=new IndexWriterConfig(analyzer);
        IndexWriter writer=null;
        try {
            writer =new IndexWriter(directory,writerConfig);
        }catch (Exception e){
            e.printStackTrace();
        }
        return writer;
    }
    public Directory getDirctory(String indexDir){
        Directory directory=null;
        try {
            directory=FSDirectory.open(Paths.get(indexDir));
        }catch (IOException e){
            e.printStackTrace();
        }
        return directory;
    }
    /**
     * 创建索引不加权
     * @throws Exception
     */
    public void Indexer()throws Exception{
       IndexWriter writer=getIndexWriter(getDirctory(indexDir));
        Document doc=null;
        for(String str:title){
            doc=new Document();
            //Lucence5.5 Fileld有多个实现,StringFIeld不分词  TextField分词
            doc.add(new StringField("theme",theme, Field.Store.YES));
            Field field=new TextField("title",str, Field.Store.YES);
            doc.add(field);
            writer.addDocument(doc);
        }
        writer.close();
    }

    /**
     * 关键命中词高亮输出处理
     * @param query
     * @param context
     * @return
     * @throws Exception
     */
    public static String getHighlighterString(Query query,String context)throws Exception{
        //对促成文档匹配的实际项进行评分
        QueryScorer scorer=new QueryScorer(query);
        //设置高亮的HTML标签格式
        Formatter  simpleHTMLFormatter=new SimpleHTMLFormatter("","");
        //实例化高亮分析器
        Highlighter highlighter=new Highlighter(simpleHTMLFormatter,scorer);
        //提供静态方法,支持从数据源中获取TokenStream,进行token处理
        TokenStream tokenStream=new CJKAnalyzer().tokenStream("title", new StringReader(context));
        return highlighter.getBestFragment(tokenStream, context);
    }
    @Test
    public void searcherTest()throws Exception{
        //  Indexer();
        IndexReader reader= DirectoryReader.open(getDirctory(indexDir));
        IndexSearcher is=new IndexSearcher(reader);
        System.out.println("总的文档数:"+reader.numDocs());
        QueryParser qp=new QueryParser("title",new CJKAnalyzer());
        String q="中国";
        Query query=qp.parse(q);
        TopDocs tDocs=is.search(query,11);
        System.out.println("查询-》"+q+"《-总共命中【"+tDocs.totalHits+"】条结果");
        for (ScoreDoc scoredoc:tDocs.scoreDocs){
            Document doc = is.doc(scoredoc.doc);
            String context=doc.get("title");
            if(context!=null){
                System.out.println(getHighlighterString(query,context));
            }

        }
    }
}
查询效果如下:

原文地址:http://www.kailing.pub/article/index/arcid/82.html

Lucene5.5入门第九篇——使用searchafter方法实现分页查询

Lucenekl 发表了文章 • 0 个评论 • 2476 次浏览 • 2016-06-24 11:25 • 来自相关话题

前言

任何数据量大的情况下,取数据的时候都需要做分页的处理,比如我们百度的时候,结果往往有上千万的结果,而当前呈现在的只有几页的内容,这就是分页的场景,lucene也提供了分页查询的支持

认识searchafter

使用IndexSearcher的searchafter方法可以轻松实现分页查询,如下图



searchafter有多个重载的方法,其中有些searchafter方法Lucene已不推荐使用了,用的多的就searchAfter(final ScoreDoc after, Query query, int numHits)

它有三个形参,分别是

after:上一页最后一个ScoreDoc;

query:query接口实现类的对象,query对象可以通过QueryParser类来创建,也可以自己new Query接口的某一个特定接口实现类;

numHits:每页显示的条数

searchafter官方文档说明地址

重点在下面

/**
 * Created by 小陈 on 2016/3/25.
 */
public class IndexerPaging {
    //测试数据,模拟数据库表结构
    private static String[] ids={"1","2","3","4","5","6"}; //用户ID
    private static String [] names={"kl","kl","kl","kl","kl","fds"};
    private static String [] describes={"shi yi ge mei nan zi","Don't know","Is an idiot\n","Is an idiot\n","Is an idiot\n","Is an idiot\n"};
    //索引存储地址
    private static String indexDir="E:\\javaEEworkspace\\LuceneDemo\\LuceneIndex";

    /**
     * 获取操作索引实体,并添加测试数据
     * @param indexDir 索引存储位置
     * @return
     * @throws Exception
     */
    public static void getIndexWriter(String indexDir)throws Exception{
        IndexWriterConfig writerConfig=new IndexWriterConfig(getAnalyzer());
        IndexWriter indexWriter=new IndexWriter(FSDirectory.open(Paths.get(indexDir)),writerConfig);
        Document document=new Document();
        //Field.Store.YES或者NO(存储域选项)
        //设置为YES表示或把这个域中的内容完全存储到文件中,方便进行文本的还原
        //设置为NO表示把这个域的内容不存储到文件中,但是可以被索引,此时内容无法完全还原(doc.get)
        for(int i=0;i1){
                 int pageIndexLast=(pageIndex-1)*pageSize-1;
                 TopDocs hits=searcher.search(query,pageIndexLast);
                 if(hits.totalHits>=pageIndexLast)
                     return hits.scoreDocs[pageIndexLast];

             }
             return null;
    }

    public static void searcher(String indexDir,String q,int pageIndex,int pageSize)throws Exception{
        Directory directory= FSDirectory.open(Paths.get(indexDir));
        IndexReader reader= DirectoryReader.open(directory);
        IndexSearcher indexSearcher=new IndexSearcher(reader);
        QueryParser queryParser=new QueryParser("names",new StandardAnalyzer());
        Query query=queryParser.parse(q);
        //分页查询
        TopDocs hits=  indexSearcher.searchAfter(getPageLastScoreDoc(pageIndex,pageSize,query,indexSearcher),query,pageSize);//查询首次的30条
        System.out.println("匹配 "+q+"查询到"+hits.totalHits+"个记录");
        for (ScoreDoc scoreDoc:hits.scoreDocs){
            Document doc=indexSearcher.doc(scoreDoc.doc);
            System.out.println(doc.get("describes"));//打印Document的fileName属性
        }
        reader.close();
        directory.close();//关闭连接
    }
    /**
     * 得到默认分词器
     * @return
     */
    public static Analyzer getAnalyzer(){
        return new StandardAnalyzer();
    }

    @Test
    public void  Test()throws Exception{
//     getIndexWriter(indexDir);
        searcher(indexDir,"kl",1,10);//查询测试
    }

}
原文地址:http://www.kailing.pub/article/index/arcid/80.html

Lucene5.5入门第八篇——使用QueryParser实现高级查询

Lucenekl 发表了文章 • 0 个评论 • 2173 次浏览 • 2016-06-24 11:23 • 来自相关话题

前言

为了解决复杂的查询业务,Lucene给我们提供了一个查询语义分析器,一套完整的语法规则,能够满足大部分的查询需求,而不用关心底层是使用什么Query实现类,就好比写sql一样。 Lucene推荐我们使用QueryParser,而不是各种Query的实现类。但是,QueryParser不能满足所有的查询有求,比如多文档域联合查询 。有时候还是需要使用到Query的相关实现类,好了,下面我们就来看看QueryParser能够解析什么语法,解决什么问题,以及多文档域的查询 


直接上代码

每个语法都可以多测试一遍,看看结果,能够加深你的理解,因为这边测试的实在是多,测试结果我就不贴了;       

ps:各个查询语义可以交叉使用的,下面代码有部分也用到了,但是这边因为是写的例子,为了能更好的区分每个语义的作用,所有没有做太多的尝试

/**
 * @author kl by 2016/3/20
 * @boke www.kailing.pub
 */
public class QueryTest {
    //索引目录
    String indexDir="E:\\LuceneIndex";
    //测试数据目录
    String dataDir="E:\\LuceneTestData";
    /**
     * Lucence5.5返回IndexWriter实例
     * @param directory
     * @return
     */
    public IndexWriter getIndexWriter(Directory directory){
        Analyzer analyzer=new StandardAnalyzer();
        IndexWriterConfig writerConfig=new IndexWriterConfig(analyzer);
        IndexWriter writer=null;
        try {
            writer =new IndexWriter(directory,writerConfig);
        }catch (Exception e){
            e.printStackTrace();
        }
        return writer;
    }
    public Directory getDirctory(String indexDir){
        Directory directory=null;
        try {
            directory= FSDirectory.open(Paths.get(indexDir));
        }catch (IOException e){
            e.printStackTrace();
        }
        return directory;
    }
    @Test
    public void TestIndexer()throws Exception{
        File[] files= new File(dataDir).listFiles();
        IndexWriter writer=getIndexWriter(getDirctory(indexDir));
        for(File file:files){
            Document doc=new Document();
            doc.add(new TextField("filePath",file.getCanonicalPath(), Field.Store.YES));
            doc.add(new TextField("context",new  FileReader(file)));
            writer.addDocument(doc);
        }
        System.out.println("总共添加了"+writer.numDocs()+"个文档");
        writer.close();
    }
    @Test
    public void testSearcher()throws  Exception{
        IndexReader reader= DirectoryReader.open(getDirctory(indexDir));
        IndexSearcher searcher=new IndexSearcher(reader);
        QueryParser queryParser=new QueryParser("context",new StandardAnalyzer());
       Query queryw=queryParser.parse("Licensor");//完整匹配分词查询
        /**
         * 通配符 ?,*的使用
         */
         Query queryy=queryParser.parse("Lice?sor");//使用?匹配单个字符查询
         Query queryx=queryParser.parse("L*r");//使用*匹配多个字符查询
        /**
         * 布尔运算AND, OR,NOT,+,-的使用,注意:一定要是大写的AND和OR,NOT
         */
        Query queryo=queryParser.parse("Licensor OR ce*");//使用OR联合多关键字查询,也可用空格代替OR
        Query queryoo=queryParser.parse(" Licensor ce*");//这个和使用OR一样的效果
        Query queryjia=queryParser.parse("+Licensor Wildcard");//+代表必须的条件,搜索文档必须包含Licensor 可能有Wildcard
        Query querya=queryParser.parse("Licensor AND ce* AND Licenso?");//使用AND取多个关键字的并集查询
        Query queryNot=queryParser.parse("'Lincensor Apache' NOT 'Apache Licensor'");//搜索Lincensor Apache而不是Apache Licensor
        Query queryjian=queryParser.parse("'Lincensor Apache' - 'Apache Licensor'");//"-"同NOT的效果一样

        /**
         * 使用正则表达式查询
         */
        Query queryRegular=queryParser.parse("/[Lab]icensor/");//这个匹配Lincensor,aicensor,bicensor分词
        Query queryRegularr=queryParser.parse("/[Lab]icenso[a-z]/");//根据需要可以更灵活的使用
        /**
         * 使用~模糊匹配查询
         * 这个要和*号的用法区分下,*号完整通配多个字符查询,而~不是简单的通配,这个模糊匹配和Lucene的评分有关
         */
        Query queryFuzzy=queryParser.parse("icensor~");//可以查到Licensor关键字,而queryParser.parse("icensor*")查不到
        Query queryFuzzyparam=queryParser.parse("Licens~1");//~后面可加0-2的整数来制定模糊匹配度,默认不加为1
        Query queryFuzzyParam=queryParser.parse("Licens cens ~0");//~还可以模糊匹配差异化N字符数的多个关键字
        /**
         * 范围查询,多用于数字和时间的查询
         */
        Query queryRange =queryParser.parse("{abc TO Licens}");//{}abc与Licenszhi间的文件,不包含
        Query queryRangex =queryParser.parse("[abc TO Licens]");//{}abc与Licenszhi间的文件,包含本身
        /**
         * 关键字加权处理查询
         */
        //默认为1,可加权可降权,可通过加权处理给匹配的结果排序
        Query queryBoosting  =queryParser.parse("Licensor Wildcard^4 ");

        /**
         * Grouping组合查询
         */
        Query queryGrouping  =queryParser.parse("(+Licensor  +Wildcard) AND easier");//可使用()组合多个条件查询

         //ps: 查询部分字符需要转义处理,如(+ - && || ! ( ) { } [ ] ^ " ~ * ? : \ /)

        /**
         * 使用MultiFieldQueryParser进行多个文档域查询
         */
        Map boost=new HashMap();
        boost.put("filePath",1.5F);//设置文档域的权值
        boost.put("context",2F);
        QueryParser multiField=new MultiFieldQueryParser(new String[]{"filePath","context"},new StandardAnalyzer(),boost);
        Query queryq=multiField.parse("lucenetestdata");

        TopDocs topDocs= searcher.search(queryq,10);
        System.out.println("查询结果共有"+topDocs.totalHits+"条");
        for(ScoreDoc scoreDoc:topDocs.scoreDocs){
            Document document=searcher.doc(scoreDoc.doc);
            System.out.println(document.get("filePath")+"--评分:"+scoreDoc.score);
        }
    }

} 
ps:代码中有大量注释,有些不一定理解到位了,深入了解 请参考官方说明:

https://lucene.apache.org/core ... rches
原文地址:http://www.kailing.pub/article/index/arcid/79.html

Lucene5.5入门第七篇——Lucene索引文档域加权

Lucenekl 发表了文章 • 0 个评论 • 2749 次浏览 • 2016-06-24 11:22 • 来自相关话题

前言

就拿百度说事吧,使用百度搜索引擎的时候,你会发现,卧槽,这什么玩意,前面的几个结果根本就不是老子要的东西,都是些推广的内容,而结果匹配度高的还排在老后面去了,百度这铲屎的干嘛吃的!这也不能怪百度,毕竟人家靠推广吃饭的,自然把交了钱的结果权值提高了 !这算文档域加权的使用场景吧

说明

所谓索引域加"权",就是根据需求的不同,对不同的关键值或者不同的关键索引分配不同的权值,因为查询的时候Lucene的评分机制和权值的高低是成正比的,这样权值高的内容更容易被用户搜索出来,而且排在前面。在Lucene3.x版本的时候可以给文档加权,到4.x版本后就取消了给文档加权了,就只有给文档域加权了,如果想达到给文档加权的效果,就要该文档的每个域都加权处理                                                                                                                                                  

ps:博主前篇博文谈过IKAnalyzer与paoding中文分词,今天我们使用的是可用于中日韩的二元分词器CJKAnalyzer

闲话少说,直接上代码,看结果


package com.kl.luceneDemo;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.cjk.CJKAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.*;
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.FSDirectory;
import org.junit.Test;
import java.io.IOException;
import java.nio.file.Paths;
/**
 * @author kl by 2016/3/19
 * @boke www.kailing.pub
 */
public class FieldSetBoostTest {
    //索引目录
    String indexDir="E:\\LuceneIndex";
    //测试数据
    String theme="中国";
    String []title={"中国是一个伟大的国家","我爱你的的祖国,美丽的中国","是什么,中国令美日等国虎视眈眈"};
    /**
     * Lucence5.5返回IndexWriter实例
     * @param directory
     * @return
     */
    public IndexWriter getIndexWriter(Directory directory){
        Analyzer analyzer=new CJKAnalyzer();//中日韩二元分词
        IndexWriterConfig writerConfig=new IndexWriterConfig(analyzer);
        IndexWriter writer=null;
        try {
            writer =new IndexWriter(directory,writerConfig);
        }catch (Exception e){
            e.printStackTrace();
        }
        return writer;
    }
    public Directory getDirctory(String indexDir){
        Directory directory=null;
        try {
            directory=FSDirectory.open(Paths.get(indexDir));
        }catch (IOException e){
            e.printStackTrace();
        }
        return directory;
    }
    /**
     * 创建索引不加权
     * @throws Exception
     */
    public void Indexer()throws Exception{
       IndexWriter writer=getIndexWriter(getDirctory(indexDir));
        Document doc=null;
        for(String str:title){
            doc=new Document();
            //Lucence5.5 Fileld有多个实现,StringFIeld不分词  TextField分词
            doc.add(new StringField("theme",theme, Field.Store.YES));
            Field field=new TextField("title",str, Field.Store.YES);
            doc.add(field);
            writer.addDocument(doc);
        }
        writer.close();
    }
    /**
     * 创建索引,指定文档域加权
     * @throws Exception
     */
    public void IndexerSetBoot()throws Exception{
        IndexWriter writer=getIndexWriter(getDirctory(indexDir));
        Document doc=null;
        for(String str:title){
            doc=new Document();
            //Lucence5.5 Fileld有多个实现,StringFIeld不分词  TextField分词
            doc.add(new StringField("theme",theme, Field.Store.YES));
            Field field=new TextField("title",str, Field.Store.YES);
            if(str.indexOf("是什么")!=-1)
                field.setBoost(2);//提高权值
            doc.add(field);
            writer.addDocument(doc);
        }
        writer.close();
    }
    @Test
    public void searcherTest()throws Exception{
        IndexerSetBoot();
//        Indexer();
        IndexReader reader= DirectoryReader.open(getDirctory(indexDir));
        IndexSearcher is=new IndexSearcher(reader);
        System.out.println("总的文档数:"+reader.numDocs());
        QueryParser qp=new QueryParser("title",new CJKAnalyzer());
        Query query=qp.parse("中国");
        TopDocs tDocs=is.search(query,11);//一次查询多少个结果
        System.out.println("总共有【"+tDocs.totalHits+"】条结果");
        for (ScoreDoc scoredoc:tDocs.scoreDocs){
            Document doc = is.doc(scoredoc.doc);
            System.out.println(doc.getField("title").stringValue());
        }
    }
}
加权和不加权的结果如下



原文地址:http://www.kailing.pub/article/index/arcid/77.html

Lucene5.5入门第六篇——Analyzer中文分词

Lucenekl 发表了文章 • 0 个评论 • 4050 次浏览 • 2016-06-24 11:18 • 来自相关话题

前言

对于中文分词这个字眼,百科是这么描述的:

中文分词(Chinese Word Segmentation) 指的是将一个汉字序列切分成一个一个单独的词。分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。我们知道,在英文的行文中,单词之间是以空格作为自然分界符的,而中文只是字、句和段能通过明显的分界符来简单划界,唯独词没有一个形式上的分界符,虽然英文也同样存在短语的划分问题,不过在词这一层上,中文比之英文要复杂的多、困难的多。

简单的说,就是把一个句子拆分成多个词,有废话的赶脚,呵呵

之前几篇博文,笔者都是用的Lucene里的StandardAnalyzer来做的分词处理,虽然在后面的Lucene版本中,

准备工作

这里先把这两个分词器加入到我们的项目中来

IKAnalyzer:IKAnalyzer是一个国人开发的开源的分词工具,下载地址:https://code.google.com/archiv ... e%3D1,GItHub地址:https://github.com/wks/ik-analyzer。推荐到GitHub上下载源码然后自己打包,项目是maven构建的,打成jar,然后在我们的项目中引用。

ps:打包项目的时候记得去掉test

paoding:paoding也是一个开源的i项目,下载地址:https://code.google.com/archiv ... loads,下载下来是一个压缩文件,里面有源码也有打包好可以直接用的jar

ps:下载paoding的时候请自行翻墙吧,这里推荐一个翻墙神器Lantern

进入正文

笔者在测试过程中并不是一番风顺啊,好多坑,下面我们来看看这些坑

IKAnlyzer的问题:

1.最新的项目也是基于Lucene3.0.3版本的,而笔者一直都是使用的最新的Lucene5.5,所以一测试就报了如下的错误

Exception in thread "main" java.lang.VerifyError: class org.wltea.analyzer.lucene.IKAnalyzer overrides final method tokenStream.(Ljava/lang/String;Ljava/io/Reader;)Lorg/apache/lucene/analysis/TokenStream;

解决:笔者有试着将IKAnlyzer项目的Lucene版本换成5.5的重新打包,然后发现行不通,改动的地方太多了,虽然IKAnlyzer项目不大,文件不多。笔者还没达到重写IKAnlyzer项目的能力,有时间可以研究研究源码,最后只有降级自己的Lucene版本了,幸好有maven,降级只要改下pom.xml就行了

paoding的问题

1.项目首先会依赖apache的commons-logging,笔者测试1.1版本通过。

2.然后就是下面的这个了 问题了,其实这个问题paoding自己的使用文档中类似的说明,(Paoding中文分词参考手册.htm)这个文档包含在了下载的压缩包中了

net.paoding.analysis.exception.PaodingAnalysisException: please set a system env PAODING_DIC_HOME or Config paoding.dic.home in paoding-dic-home.properties point to the dictionaries!

解决:就是指定paoding的一个字典文件目录,这个文件在下载下来的压缩包中的dic中,

三种解决方案:

(1).你可以解压缩jar,然后把paoding-dic-home.properties文件中的paoding.dic.home指定你的doc目录,重新压缩,把后缀换成jar就行了。

(2).就是参照官方的说明,把doc目录添加到环境变量中

(3).把doc放在项目目录下

3.paoding还有个问题就是Lucene3.0.3都不兼容了,笔者只好又把Lucene版本降到2.2.0来测试了

越过那些沟沟坎坎终于要见真功夫了,不多说,直接上代码,上图


package com.kl.Lucene;
import net.paoding.analysis.analyzer.PaodingAnalyzer;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.TermAttribute;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;
import java.io.StringReader;
/**
 * @author kl by 2016/3/14
 * @boke www.kailing.pub
 */
public class AnalyzerTest {
    //测试数据
    public static String testData="中文分词(Chinese Word Segmentation) 指的是将一个汉字序列切分成一" +
            "一个单独的词。分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。";
    /**
     * 得到IKAnalyzer分词器
     * @return
     */
    public static Analyzer getIKAnalyzer(){
        return  new IKAnalyzer();
    }
    /**
     * 得到Paoding分词器
     * @return
     */
    public static Analyzer getPaoding(){
        return new PaodingAnalyzer();
    }
    /**
     * 测试IKAnalyzer
     * @throws Exception
     */
    @Test
    public void TestIKAnalyzer()throws Exception{
        Analyzer analyzer =getIKAnalyzer();
        TokenStream tokenStream = analyzer.tokenStream("", new StringReader(testData));
        tokenStream.addAttribute(TermAttribute.class);
        System.out.println("分词数据:"+testData);
        System.out.println("=====IKAnalyzer的分词结果====");
        while (tokenStream.incrementToken()) {
            TermAttribute termAttribute = tokenStream.getAttribute(TermAttribute.class);
            System.out.println(new String(termAttribute.term()));
            termAttribute.termLength();
        }

    }
    /**
     * 测试Paoding
     * @throws Exception
     */
    @Test
    public void TestPaoding()throws  Exception{
        Analyzer analyzer =getPaoding();
        TokenStream ts = analyzer.tokenStream("",  new StringReader(testData));
        System.out.println("分词数据:"+testData);
        System.out.println("=====Paoding的分词结果====");
        Token t;
//        while ((t = ts.next()) != null) {
//            System.out.println(t.termText());
//        }
    }


}
测试数据:中文分词(Chinese Word Segmentation) 指的是将一个汉字序列切分成一个单独的词。分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。

测试结果如下:





从结果上看,IKAnalyzer和paoding的分词相差无几,IKAnlyzer比paoding的分词粒度更细,这个可以查看他们的分词字典文件去分析

后记:除了上面介绍的两种分词,常用的还有中日韩二元分词器CJKAnalyzer,以及lucene基于中科院分词实现的SmartChineseAnalyzer,其中cjk在lucene-common的jar包里了,SmartChineseAnalyzer需要另外引入jar,如下pom依赖

        <!--公共的分词器,包含大多数的语言分词-->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-common</artifactId>
            <version>5.5.0</version>
        </dependency>
        <!--基于中科院的中文分词-->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-smartcn</artifactId>
            <version>5.5.0</version>
        </dependency>


原文地址:http://www.kailing.pub/article/index/arcid/76.html

Lucene5.5入门第五篇——Lucene索引的【增删改查】

Lucenekl 发表了文章 • 0 个评论 • 2896 次浏览 • 2016-06-24 11:15 • 来自相关话题

前言

从入门的demo,到了解原理到了解结构,继而学习工具,现在我们可以用Lucene来做简单的数据增删改查操作了

直接上代码

ps:代码注释比较全,鉴于作者的水平,有些东西可能未理解到位。推荐使用Luke来配合测试,了解Luke可参考我的上一篇博文:http://www.kailing.pub/article/index/arcid/74.html

package com.kl.Lucene;
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.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.junit.Test;
import java.nio.file.Paths;
/**
 * @author kl by 2016/3/14
 * @boke www.kailing.pub
 */
public class IndexerCURD {
    //测试数据,模拟数据库表结构
    private static String ids={"1","2","3"}; //用户ID
    private static String  names={"kl","wn","sb"};
    private static String  describes={"shi yi ge mei nan zi","Don't know","Is an idiot\n"};
    //索引存储地址
    private static String indexDir="E:\\javaEEworkspace\\LuceneDemo\\LuceneIndex";
    /**
     * 获取操作索引实体,并添加测试数据
     * @param indexDir 索引存储位置
     * @return
     * @throws Exception
     */
    public static IndexWriter getIndexWriter(String indexDir)throws Exception{
        IndexWriterConfig writerConfig=new IndexWriterConfig(getAnalyzer());
        IndexWriter indexWriter=new IndexWriter(getDirectory(indexDir),writerConfig);
        Document document=new Document();
        //Field.Store.YES或者NO(存储域选项)
        //设置为YES表示或把这个域中的内容完全存储到文件中,方便进行文本的还原
        //设置为NO表示把这个域的内容不存储到文件中,但是可以被索引,此时内容无法完全还原(doc.get)
        for(int i=0;i<ids.length;i++){
            document.add(new StringField("ids",ids[i], Field.Store.YES));
            document.add(new StringField("names",names[i], Field.Store.YES));
            document.add(new TextField("describes",describes[i], Field.Store.YES));
            indexWriter.addDocument(document);
        }
        return indexWriter;
    }
    /**
     * 得到默认分词器
     * @return
     */
    public static Analyzer getAnalyzer(){
        return  new StandardAnalyzer();
    }
    /**
     * 得到索引磁盘存储器
     * @param indexDir 存储位置
     * @return
     */
    public static Directory getDirectory(String indexDir){
        Directory directory=null;
        try {
             directory= FSDirectory.open(Paths.get(indexDir));
        }catch (Exception e){
            e.printStackTrace();
        }
        return  directory;
    }
    /**
     * 获取读索引实体,并打印读到的索引信息
     * @return
     */
    public  static IndexReader getIndexReader(){
        IndexReader reader=null;
        try {
            reader= DirectoryReader.open(getDirectory(indexDir));
            //通过reader可以有效的获取到文档的数量
            System.out.println("当前存储的文档数::"+reader.numDocs());
            System.out.println("当前存储的文档数,包含回收站的文档::"+reader.maxDoc());
            System.out.println("回收站的文档数:"+reader.numDeletedDocs());

        } catch (Exception e) {
            e.printStackTrace();
        }
        return reader;
    }

    /**
     * 写索引测试,借助Luke观察结果
     * @throws Exception
     */
    @Test
    public void Testinsert() throws  Exception{
        IndexWriter writer=getIndexWriter(indexDir);
        writer.close();
        getIndexReader();
    }
    /**
     * 删除索引测试,借助Luke观察结果
     * @throws Exception
     */
    @Test
    public void TestDelete()throws Exception{
        //测试删除前我们先把上次的索引文件删掉,或者换个目录
        IndexWriter writer=getIndexWriter(indexDir);
        QueryParser parser=new QueryParser("ids", getAnalyzer());//指定Document的某个属性
        Query query=parser.parse("2");//指定索引内容,对应某个分词
        Term term=new Term("names","kl");
        //参数是一个选项,可以是一个query,也可以是一个term,term是一个精确查找的值
        writer.deleteDocuments(query);//此时删除的文档并不会被完全删除,而是存储在一个回收站中的,可以恢复
         writer.forceMergeDeletes();//强制合并删除的索引信息,索引量大的时候不推荐使用,真正的删除
       // writer.commit(); //更改索引要提交,和提交数据库事务一个概念,真正的删除
        writer.close();
        getIndexReader();
    }
    /**
     * 更新操作测试,借助Luke观察结果
     * @throws Exception
     */
    @Test
    public void TestUpdate()throws Exception{
       // Lucene并没有提供更新,这里的更新操作相当于新增,他并不会去掉原来的信息
        IndexWriter writer = getIndexWriter(indexDir);
        try {
            Document doc = new Document();
            doc.add(new StringField("id","1",Field.Store.YES));
            doc.add(new StringField("names","ckl",Field.Store.YES));
            doc.add(new StringField("describes","chenkailing",Field.Store.NO));
            writer.updateDocument(new Term("id","1"), doc);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
                if(writer!=null) writer.close();
        }
    }
    /**
     * 查询测试
     */
    @Test
    public void TestSearchaer(){
        try {
            IndexReader reader = getIndexReader();
            IndexSearcher searcher = new IndexSearcher(reader);
            QueryParser parser=new QueryParser("names", getAnalyzer());//指定Document的某个属性
            Query query=parser.parse("kl");//指定索引内容,对应某个分词
            Term term=new Term("names","kl");
            //参数是一个选项,可以是一个query,也可以是一个term,term是一个精确查找的值
            TopDocs hits = searcher.search(query, 10);
            for(ScoreDoc sd:hits.scoreDocs) {
                Document doc = searcher.doc(sd.doc);
                System.out.println(
                        doc.get("names")+"["+doc.get("describes")+"]-->"+doc.get("ids"));
            }
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}[/i][/i][/i]
[i][i][i]原文地址:http://www.kailing.pub/article/index/arcid/75.html
[/i][/i][/i]

Lucene5.5入门第四篇——Lucene索引查看工具Luke

Lucenekl 发表了文章 • 0 个评论 • 2801 次浏览 • 2016-06-24 11:14 • 来自相关话题

前言

Luke是一个用于Lucene搜索引擎的,方便开发和诊断的第三方工具,它可以访问现有Lucene的索引,并允许您显示和修改。如果我们把Lucene的索引比作数据库数据的话,那么Luke就是一个管理数据的客户端(DBMS)。我们开发Lucene的时候可以借助这个工具来提高我们的开发效率

准备工作

Luke是一个开源的i项目,项目托管在GitHub上,地址https://github.com/DmitryKey/luke,选好我们的Luke分支下载下来

ps:Lucene更新迭代的很快,每个版本的变化也比较大,所以我们在选Luke版本的时候也要选择对应的分支下对应的版本,不然就gg了,笔者这里的Lucene是最新的5.X版本,当然Luke也是选的最新的

Luke是一个maven项目,下载好后,install下,会打成一个jar包,直接双击jar就可以运行

ps:最新的Luke的使用的是jdk1.8,其他版本的不清楚,可以去pom.xml文件看下

运行后的界面如下,我这里已选则好索引目录了



图解

1处信息可以看出这个Document有几个Field,以及每个Field的分词个数,百分占比,编码

2.处信息是一个统计区,列出了有几个Document,Document有几个FIeld,总共多少个分词

3.处可以重新打开索引(当索引变化时),提交更改

4.处是索引的详细信息,可以看出每个分词出现的频次,以及对于的Field

使用Luke

上图可以看到第一个选项卡OverView的功能,接下来就看看其他的选项卡的功能

documents选项卡是用来进行文档的操作和查看的,比如文件的删除、添加。下面一个大listview就可以用来查看文档的详细信息了,是不是和DBMS的查看表数据非常的像呢?上面有两个查找文档的方法,根据文档编号来查找和根据词来查找了,其实这个就是搜索了,详情如下图

search选项卡是我认为最有用的一个界面了,其中我们可以在这里进行索引的搜索测试,可以编写最的lucene搜索语句,然后可以看到语句解析后的query树,这样就可以知道为什么我们有些查询会查询不到我们想要的信息了,然后还可以选择进行搜索的分词器、默认字段和重复搜索次数的(可以通过多次搜索来获取平均一个搜索过程的耗时长短,这个对查询的性能测试时非常有用的),然后下面的listview中就会列出一个搜索的的文档的所有保存的(store)字段的值,下面可以看到查询花费的时间。详情如下图


Commits选项卡就是用来查看每个索引相关文件的一些属性的界面,具体的话,可以通过这个界面分析下索引文件的多少大小,是否需要优化或者合并等等。详情如下图

最后一个plugins选项卡,就是可以看到luke提供的各种插件,我认为比较有用的还是那个分词工具,提供一个分词的类,然后下面文本框输入一段文本,然后就可以让这个工具帮你分词,你可以看到详细的分词信息。详情如下图


原文地址:http://www.kailing.pub/article/index/arcid/74.html