lucene +Ik-Analyzer

本文详细介绍使用Lucene4.10.3结合IKAnalyzer2012进行中文分词、索引创建、查询、更新及删除的具体实现过程。通过对比不同中文分词器,选择了IKAnalyzer作为最佳方案。并提供了完整的代码示例,包括如何创建索引、执行查询、更新索引及删除索引等关键操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


版本选择:
Lucene 4.10.3+IKAnalyzer2012FF_u1
代码地址:https://gitee.com/fenglifengli/lucene4.git

一、中文分词的选择

个人选择:IKAnalyzer

分词器说明
jcseg中文分词器听说分词准确率高达98.4%,持中文人名识别, 同义词匹配。但是我搞了半天都似乎和lucene4.10.3不兼容
IKAnalyzer轻量级,还不错
PaodingAnalyzer庖丁法,这个好像要安装词典
ChinesAnalyzer只能进行单字分析

二、索引创建、查询、更新、删除

问题描述:就是给一个标签库,在给一个输入字符串。对输入字符串进行中文划分产生查询条件,在标签库中查找满足条件的所有标签。

2.1 创建索引

创建索引,索引可以创建到内存中。也可以创建到磁盘上。

 /**
     * 对创建索引到磁盘和创建索引到内存的整合
     * @param marks 标签库
     * @param intoRAM 是否将索引建立到内存中
     * @return 返回索引的目录
     * @throws IOException
     */
    public static Directory createIndex(Map<String,String> marks,boolean intoRAM) throws IOException {
        Directory directory;
        if(intoRAM==true){
        	//RAMDirectory就是将索引创建到内存中去,当关闭程序时,就将索引清除
            directory=new RAMDirectory();
        }else {
            //获取当前项目的路径
            String relativelyPath=System.getProperty("user.dir");
            //下面分隔符要看是部署到那种系统中决定
            File indexDir = new File(relativelyPath+"/luceneIndex");
            directory=FSDirectory.open(indexDir);
        }
        //Analyzer analyzer= new ChineseAnalyzer();//单字分词
        Analyzer analyzer=new IKAnalyzer();
        //Analyzer analyzer=new PaodingAnalyzer();//这个好像要安装词典
        //Analyzer analyzer=new CJKAnalyzer(Version.LUCENE_4_10_3);//二元分词
        IndexWriterConfig writerConfig = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer);
        IndexWriter indexWriter = new IndexWriter(directory, writerConfig);
        //删除索引
        indexWriter.deleteAll();
        for(String key:marks.keySet()){
            Document document=new Document();
            document.add(new Field("label",marks.get(key), TextField.TYPE_STORED));
            document.add(new Field("id",key, TextField.TYPE_STORED));
            indexWriter.addDocument(document);
        }
        indexWriter.close();
        return directory;
    }

2.2 查询

  • 首先,我们将输入字符串进行中文划分,选择的是IKAnalyzer
   /**
     * 使用指定的分词器对输入进行中文分词
     * @param input 输入字符
     * @param analyzer 分析器(单字分析用ChineseAnalyzer,其它可以选择IKAnalyzer)
     * @return
     */
    public static ArrayList<String> getQueryArray(String input,Analyzer analyzer){
        ArrayList<String> result=new ArrayList<String>();
        //Analyzer analyzer= new ChineseAnalyzer();//单字分词
        // Analyzer analyzer=new IKAnalyzer();
        //Analyzer analyzer=new PaodingAnalyzer();//这个好像要安装词典
        //Analyzer analyzer = new IKAnalyzer();
        //Analyzer analyzer=new JcsegAnalyzer5X(JcsegTaskConfig.SIMPLE_MODE);//jcseg2.1.0,1.9.9,2.0.1好像和lucene4.10.3不兼容
        TokenStream stream = null;

        try {
            stream = analyzer.tokenStream("myfield", input);
            stream.reset();
            CharTermAttribute offsetAtt = stream.addAttribute(CharTermAttribute.class);
            while (stream.incrementToken()) {
                //System.out.println(offsetAtt.toString());
                result.add(offsetAtt.toString());
            }

            stream.end();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            try {
                stream.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return result;
    }

该方法是使用IKAnalyzer(当然,也可以选择兼容的分词器)对字符串进行分词

测试代码:

 @Test
    public void getQueryArrayTest(){
        ChineseAnalyzer chineseAnalyzer=new ChineseAnalyzer();
        StandardAnalyzer standardAnalyzer=new StandardAnalyzer(Version.LUCENE_4_10_3);
        CJKAnalyzer cjkAnalyzer=new CJKAnalyzer(Version.LUCENE_4_10_3);
        IKAnalyzer ikAnalyzer=new IKAnalyzer();
        ArrayList<String> querys= IndexManagerUtils.getQueryArray("IndexReader和IndexWriter都由删除索引的功能,但这两者是有区别的",ikAnalyzer);
        for(int i=0;i<querys.size();++i){
            System.out.println(querys.get(i));
        }
    }

分词结果:

indexreader
和
indexwriter
都由
删除
索引
的
功能
但
这两者
两者
两
者
是
有
区别
别的
的
  • 组合查询(以“或”的形式)
 /**
     * 根据所给索引目录与条件查询结果
     * @param conditions 多组条件
     * @param directory 索引的目录
     * @return
     */
    public static Map<String,String> searchByConditions(ArrayList<String> conditions,Directory directory) throws IOException {
        DirectoryReader ireader = DirectoryReader.open(directory);
        IndexSearcher searcher = new IndexSearcher(ireader);
        BooleanQuery booleanQuery = new BooleanQuery();
        for(int i=0;i<conditions.size();++i){
            Term term=new Term("label",conditions.get(i));
            TermQuery termQuery=new TermQuery(term);
            booleanQuery.add(termQuery, BooleanClause.Occur.SHOULD);
        }
        ScoreDoc[] scoreDocs = searcher.search(booleanQuery,null, 1000).scoreDocs;
        Map<String, String> result = getResultMapByScoreDoc(searcher, scoreDocs);
        return  result;
    }

/**
     * 从查询结果scoreDocs中生成Map
     * @param searcher
     * @param scoreDocs
     * @return
     * @throws IOException
     */
    private static Map<String, String> getResultMapByScoreDoc(IndexSearcher searcher, ScoreDoc[] scoreDocs) throws IOException {
        Map<String,String> result=new HashMap<String, String>();
        for(int i=0;i<scoreDocs.length;++i){
            Document hit = searcher.doc(scoreDocs[i].doc);//doc是一个整数,应该存到是和文档在索引中位置有关的信息吧
            result.put(hit.getField("id").stringValue(),hit.getField("label").stringValue());
        }
        return result;
    }

2.3 更新索引,是以IndexWriter进行更新的,要记得close,不然不会更新。如果索引中没有需要更新的文档,那么会将文档add到索引中去。

//根据id更新索引
    public static void updateIndex(Map<String,String> someMarks) throws IOException {
          //创建IKAnaylzer
        Analyzer analyzer=new IKAnalyzer();
        //先更新ikDirectory
        IndexWriterConfig writerConfig = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer);
        IndexWriter indexWriter = new IndexWriter(ikDirectory, writerConfig);
        for(String key:someMarks.keySet()){
            Document document=new Document();
            document.add(new Field("label",someMarks.get(key), TextField.TYPE_STORED));
            document.add(new Field("id",key,TextField.TYPE_STORED));
            Term term=new Term("id",key);
            indexWriter.updateDocument(term,document);
        }
        indexWriter.close();
        //再更新chDirectory
        analyzer=new ChineseAnalyzer();
        writerConfig=new IndexWriterConfig(Version.LUCENE_4_10_3,analyzer);
        indexWriter=new IndexWriter(chDirectory,writerConfig);
        for(String key:someMarks.keySet()){
            Document document=new Document();
            document.add(new Field("label",someMarks.get(key), TextField.TYPE_STORED));
            document.add(new Field("id",key,TextField.TYPE_STORED));
            Term term=new Term("id",key);
            indexWriter.updateDocument(term,document);
        }
        indexWriter.close();//注意这里
    }

2.4 删除索引,使用IndexWriter的deleteAll方法,并且注意close.

//完全删除索引
    public static void deleteIndex() throws IOException {
        Analyzer analyzer=new IKAnalyzer();
        IndexWriterConfig writerConfig = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer);
        IndexWriter indexWriter = new IndexWriter(ikDirectory, writerConfig);
        //删除索引
        indexWriter.deleteAll();
        indexWriter.close();

        analyzer=new ChineseAnalyzer();
        writerConfig = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer);
        indexWriter = new IndexWriter(chDirectory, writerConfig);
        //删除索引
        indexWriter.deleteAll();
        indexWriter.close();
    }

参考文献

Lucene的各中文分词比较
lucene7.1.0 (二) helloworld
lucene4.10.3入门教程
Lucene 中文分词器 Ik-Analyzer 使用教程
lucene利用BooleanQuery进行多个Query组合查询
Lucene之模糊、精确、匹配、范围、多条件查询-yellowcong
获取java项目根目录
lucene的中文分词器jcseg和IK Analyzer分词器及其使用说明
lucene索引的更新和删除

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值