首页 > 代码库 > lucene内存索引库、分词器

lucene内存索引库、分词器

内存索引库

特点

        

         在内存中开辟一块空间,专门为索引库存放。这样有以下几个特征:

1)    因为索引库在内存中,所以访问速度更快。

2)    在程序退出时,索引库中的文件也相应的消失了。

3)    如果索引库比较大,必须得保证足够多的内存空间。

编码

在cn.hqu.directory 下新建:DirectoryTest

 

/**

 * 1、能不能设置很多个索引库

 *    可以设置很多个索引库

 * 2、索引库能不能合并起来

 *    如果是内存索引库

 *      Directory ramDirectory = new RamDirectory(Directory d);

 *         这样就可以把一个索引库放入到内存索引库中

 *    利用IndexWriter.addIndexesNoOptimize方法可以把很多个索引库进行合并操作

 * 3、应用程序能不能在内存中和索引库进行交互

 * @author Administrator

 *

 */

public class DirectoryTest {

    /**

     * 内存索引库

     *   *  速度比较快

     *   *  数据是暂时的

     *   *  内存索引库和文件索引库的特点正好互补

     */

    @Test

    public void testRam() throws Exception{

        Directory directory = new RAMDirectory();

        IndexWriter indexWriter = new IndexWriter(directory,LuceneUtils.analyzer,

                MaxFieldLength.LIMITED);

        Article article = new Article();

        article.setId(1L);

        article.setTitle("lucene可以做搜索引擎");

        article.setContent("baidu,google都是很好的搜索引擎");

        indexWriter.addDocument(DocumentUtils.article2Document(article));

        indexWriter.close();

        this.showData(directory);

    }

   

    private void showData(Directory directory) throws Exception{

        IndexSearcher indexSearcher = new IndexSearcher(directory);

        QueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_30,

                new String[]{"title","content"},LuceneUtils.analyzer);

        Query query = queryParser.parse("lucene");

        TopDocs topDocs =indexSearcher.search(query, 10);

        ScoreDoc[] scoreDocs = topDocs.scoreDocs;

        List<Article> articleList = new ArrayList<Article>();

        for(ScoreDoc scoreDoc:scoreDocs){

            Document document =indexSearcher.doc(scoreDoc.doc);

            articleList.add(DocumentUtils.document2Article(document));

        }

       

        for(Article article:articleList){

            System.out.println(article.getId());

            System.out.println(article.getTitle());

            System.out.println(article.getContent());

        }

    }

}

 

         在执行完这段代码以后,并没有在磁盘上出现索引库。所以单独使用内存索引库没有任何意义。

文件索引库与内存索引库的结合


                            当应用程序启动的时候,从文件索引库加载文件到内存索引库。应用程序直接与内存索引库交互。当应用程序退出的时候,内存索引库把数据再次保存到文件索引库,完成文件的保存工作。

 

    /**

     * 文件索引库和内存索引库的结合,提高效率

     */

    @Test

    public void testRamAndFile() throws Exception{

        /**

         *1、当应用程序启动的时候,把文件索引库的内容复制到内存库中

         *2、让内存索引库和应用程序交互

         *3、把内存索引库的内容同步到文件索引库

         */

        Directory fileDirectory =FSDirectory.open(new File("./indexDir"));

        Directory ramDirectory = new RAMDirectory(fileDirectory);

        IndexWriter ramIndexWriter = new IndexWriter(ramDirectory,

                LuceneUtils.analyzer,MaxFieldLength.LIMITED);

        IndexWriter fileIndexWriter = new IndexWriter(fileDirectory,

                LuceneUtils.analyzer,true,MaxFieldLength.LIMITED);

        /**

       在内存索引库中根据关键词查询在

         *启动的时候,把文件目录的索引库加载到内存目录中,

 * 退出时把内存目录的索引库保存到文件目录

         */

        this.showData(ramDirectory);

       

       

        System.out.println("上面的是从内存索引库中查询出来的");

       

        /**

         *把一条信息插入到内存索引库

         */

        Article article = new Article();

        article.setId(1L);

        article.setTitle("lucene可以做搜索引擎");

        article.setContent("baidu,google都是很好的搜索引擎");

        ramIndexWriter.addDocument(DocumentUtils.article2Document(article));

        ramIndexWriter.close();

       

        /*

         *把内存索引库中的内容同步到文件索引库中

         */

        fileIndexWriter.addIndexesNoOptimize(ramDirectory);

        fileIndexWriter.close();

        this.showData(fileDirectory);

        System.out.println("上面的是从文件索引库中查询出来的");

      }

 

               说明:

1)    Directory ramdirectory = newRAMDirectory(filedirectory);把filedirectory这个索引库加载到ramdirectory内存库中

2)    IndexWriter的构造函数:

 

       IndexWriterfileIndexWriter = new IndexWriter(fileDirectory,

              LuceneUtils.analyzer,true,MaxFieldLength.LIMITED);

 

                         True     重新创建一个或者覆盖(选择)

                         False    追加

1.             分词器

1.1英文分词器

         步骤:Creates a searcher searching the index in the nameddirectory

1)    切分关键词

Creates  

a  

searcher 

searching 

the 

index 

the 

named 

directory

2)    去除停用词

停用词:有些词在文本中出现的频率非常高。但对本文的语义产生不了多大的影响。例如英文的a、an、the、of等。或中文的”的、了、呢等”。这样的词称为停用词。停用词经常被过滤掉,不会被进行索引。在检索的过程中,如果用户的查询词中含有停用词,系统会自动过滤掉。停用词可以加快索引的速度,减少索引库文件的大小。

Creates

searcher

searching

index

named

directory

3)    转为小写(搜索时不区分大小写,因为分词器会帮你转化)

creates

searcher

searching

index

named

directory

1.1.1代码:

    @Test

    public voidtestEn() throwsException{

       /**

        * Creates a searcher searching the index inthe named directory

        */

       /**

        * 1、切分关键词

        * 2、去掉停用词

        * 3、把大写转化成小写

        */

       Stringtext = "Creates a searcher searching the index in the nameddirectory";

       Analyzeranalyzer = new StandardAnalyzer(Version.LUCENE_30);

       this.testAnalyzer(analyzer,text);

    }

 

    /**

     * 经过该方法可以把分词后的结果输出

     * @param analyzer

     * @param text

     * @throws Exception

     */

     private voidtestAnalyzer(Analyzer analyzer,String text)throwsException{

         TokenStream tokenStream = analyzer.tokenStream("content",new StringReader(text));

         tokenStream.addAttribute(TermAttribute.class);

         while(tokenStream.incrementToken()){

              TermAttribute termAttribute =tokenStream.getAttribute(TermAttribute.class);

              System.out.println(termAttribute.term());

         }

     }

1.2中文分词器

1.2.1单字分词

       /**

        * 单字分词

        */

       Analyzeranalyzer = newChineseAnalyzer();

       Stringtext = "新北校区有一个是UFO";

       this.testAnalyzer(analyzer,text);

 

                   把汉字一个字一个字分解出来。效率比较低。

1.2.2二分法分词

       Analyzeranalyzer = newCJKAnalyzer(Version.LUCENE_30);

       Stringtext = "新北校区有一个是UFO";

       this.testAnalyzer(analyzer, text);

 

把相邻的两个字组成词分解出来,效率也比较低。而且很多情况下分的词不对。

1.2.3词库分词(IKAnalyzer)

 

       Analyzeranalyzer = newIKAnalyzer();

       Stringtext = "北京美女";

       this.testAnalyzer(analyzer, text);

导入IKAnalyzer的jar包。

网盘年下载:http://pan.baidu.com/s/1nt9eqVZ

基本上可以把词分出来(经常用的分词器)


1.2.4词库的扩充

                  

                   “新北小去的阿尔法四了”分此后的结果为:

                   新、北、小、去、阿尔法、四、了

         在src下新建:ext_stopword.dic、IKAnalyzer.cfg.xml、mydict.dic。

ext_stopword.dic为停止词的词库,词库里的词都被当作为停止词使用。

IKAnalyzer.cfg.xml为IKAnalyzer的配置文件。

 

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEpropertiesSYSTEM"http://java.sun.com/dtd/properties.dtd"> 

<properties> 

    <comment>IK Analyzer 扩展配置</comment>

   

    <entrykey="ext_dict">/mydict.dic</entry> 

     

    <entrykey="ext_stopwords">/ext_stopword.dic</entry>

   

</properties>

                            Key为ext_stopwords 为停止词所在的位置。

      Key为ext_dict为配置自己的扩展字典所在的位置。如图所示可以在mydict.dic中添加自己所需要的词。如:”新北小去”

      添加完以后分词器分” “新北小去的阿尔法四了”结果为:

                   新北小去、阿尔法、四、了

ext_stopword.dic如下:






使

























mydict.dic 内容如下:

新北小去

1.2.5修改LuceneUtils类

                   analyzer = new IKAnalyzer();

 

                   以后用的分词库为IKAnalyzer中文分词库。