hankcs / hanlp-lucene-plugin

HanLP中文分词Lucene插件,支持包括Solr在内的基于Lucene的系统
http://www.hankcs.com/nlp/segment/full-text-retrieval-solr-integrated-hanlp-chinese-word-segmentation.html
Apache License 2.0
296 stars 99 forks source link

偏移量错误 #10

Closed drmam closed 8 years ago

drmam commented 8 years ago

作者你好,我用tika读取文件之后就会出现这个错误 tika是1.6的,hanlp-solr是最新版,下面代码就是您文件中单元测试的代码。测试文件test 测试结果如下: 软件工程专业是2002年国家教育部新增专业,随着计算机应用领域的不 断扩大及中国经济建设的不断发展,软件工程专业将成为一个新的热门专业。软 件工程专业以计算机科学与技术学科为基础,

Query = text:专业 命中:1 测试回测换行符 , 0.2795085 文中有3个词汇”专业“只命中一个,如果使用ik分词器是就不会报错的,希望解决一下。

test.docx

org.apache.lucene.search.highlight.InvalidTokenOffsetsException: Token , exceeds length of provided text sized 98 at org.apache.lucene.search.highlight.Highlighter.getBestTextFragments(Highlighter.java:225) at org.apache.lucene.search.highlight.Highlighter.getBestFragments(Highlighter.java:156) at org.apache.lucene.search.highlight.Highlighter.getBestFragment(Highlighter.java:102) at org.apache.lucene.search.highlight.Highlighter.getBestFragment(Highlighter.java:80) at com.lib.service.user.HighLighterTest.displayHtmlHighlight(HighLighterTest.java:181) at com.lib.service.user.HighLighterTest.testHightlight(HighLighterTest.java:116) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:483) at junit.framework.TestCase.runTest(TestCase.java:176) at junit.framework.TestCase.runBare(TestCase.java:141) at junit.framework.TestResult$1.protect(TestResult.java:122) at junit.framework.TestResult.runProtected(TestResult.java:142) at junit.framework.TestResult.run(TestResult.java:125) at junit.framework.TestCase.run(TestCase.java:129) at junit.framework.TestSuite.runTest(TestSuite.java:255) at junit.framework.TestSuite.run(TestSuite.java:250) at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:84) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

/*

import junit.framework.TestCase; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.TextField; import org.apache.lucene.index.; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.; import org.apache.lucene.search.highlight.*; import org.apache.lucene.store.Directory; import org.apache.lucene.store.LockObtainFailedException; import org.apache.lucene.store.RAMDirectory; import org.apache.tika.metadata.Metadata; import org.apache.tika.parser.AutoDetectParser; import org.apache.tika.parser.ParseContext; import org.apache.tika.parser.Parser; import org.apache.tika.parser.txt.TXTParser; import org.apache.tika.sax.BodyContentHandler; import org.junit.Test; import org.xml.sax.ContentHandler;

import com.hankcs.lucene.HanLPAnalyzer;

import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Scanner;

/**

hankcs commented 8 years ago

我没有触发这个问题:

    public void testHightlight() throws Exception
    {
        // Lucene Document的主要域名
        String fieldName = "text";

        // 实例化Analyzer分词器
        Analyzer analyzer = new HanLPAnalyzer();

        Directory directory = null;
        IndexWriter iwriter;
        IndexReader ireader = null;
        IndexSearcher isearcher;
        try
        {
            //索引过程**********************************
            //建立内存索引对象
            directory = new RAMDirectory();

            //配置IndexWriterConfig
            IndexWriterConfig iwConfig = new IndexWriterConfig(analyzer);
            iwConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
            iwriter = new IndexWriter(directory, iwConfig);
            {
                // 加入一个文档
                Document doc = new Document();
                doc.add(new TextField(fieldName, "       软件工程专业是2002年国家教育部新增专业,随着计算机应用领域的不\n" +
                        "断扩大及中国经济建设的不断发展,软件工程专业将成为一个新的热门专业。软\n" +
                        "件工程专业以计算机科学与技术学科为基础,\n", Field.Store.YES));
                doc.add(new TextField("title", "test.docx", Field.Store.YES));
                iwriter.addDocument(doc);
            }
            {
                // 再加入一个
                Document doc = new Document();
                doc.add(new TextField(fieldName, "\n\n   \n程序员\n\n喜欢黑夜", Field.Store.YES));
                doc.add(new TextField("title", "关于程序员", Field.Store.YES));
                iwriter.addDocument(doc);
            }
            iwriter.close();

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

            String keyword = "专业";
            //使用QueryParser查询分析器构造Query对象
            QueryParser qp = new QueryParser(fieldName, analyzer);
            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 < Math.min(5, scoreDocs.length); ++i)
            {
                Document targetDoc = isearcher.doc(scoreDocs[i].doc);
                System.out.print(targetDoc.getField("title").stringValue());
                System.out.println(" , " + scoreDocs[i].score);

                String text = targetDoc.get(fieldName);
                System.out.println(displayHtmlHighlight(query, analyzer, fieldName, text, 200));
            }
        }
        catch (CorruptIndexException e)
        {
            e.printStackTrace();
        }
        catch (LockObtainFailedException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (ParseException e)
        {
            e.printStackTrace();
        }
        catch (InvalidTokenOffsetsException 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();
                }
            }
        }
    }

    /**
     * 获取高亮显示结果的html代码
     *
     * @param query        查询
     * @param analyzer     分词器
     * @param fieldName    域名
     * @param fieldContent 域内容
     * @param fragmentSize 结果的长度(不含html标签长度)
     * @return 结果(一段html代码)
     * @throws IOException
     * @throws InvalidTokenOffsetsException
     */
    static String displayHtmlHighlight(Query query, Analyzer analyzer, String fieldName, String fieldContent, int fragmentSize) throws IOException, InvalidTokenOffsetsException
    {
        //创建一个高亮器
        Highlighter highlighter = new Highlighter(new SimpleHTMLFormatter("【", "】"), new QueryScorer(query));
        Fragmenter fragmenter = new SimpleFragmenter(fragmentSize);
        highlighter.setTextFragmenter(fragmenter);
        return highlighter.getBestFragment(analyzer, fieldName, fieldContent);
    }
hankcs commented 8 years ago

输出:

Query = text:专业 命中:1 test.docx , 0.25 软件工程【专业】是2002年国家教育部新增【专业】,随着计算机应用领域的不 断扩大及中国经济建设的不断发展,软件工程【专业】将成为一个新的热门专业。软 件工程【专业】以计算机科学与技术学科为基础,

hankcs commented 8 years ago

命中数量指的是文档数量,不是词语数量。

hankcs commented 8 years ago

建议你把String fileName=Parser("C:\Users\drmam\Desktop\test.docx");的结果给我一份,也就是fileName具体存的是什么。

请通过如下方式给我: 你必须在这句话上下一个断点,将fileName的值复制到剪切板,然后 String content = "粘贴一下";

drmam commented 8 years ago

我给你文件了呀

hankcs commented 8 years ago

我没有tika呀

drmam commented 8 years ago

那个29m这个可以上传吗

hankcs commented 8 years ago

不需要上传啊,你按说的把字符串复制出来给我不就行了

drmam commented 8 years ago
   软件工程专业是2002年国家教育部新增专业,随着计算机应用领域的不

断扩大及中国经济建设的不断发展,软件工程专业将成为一个新的热门专业。软 件工程专业以计算机科学与技术学科为基础,

hankcs commented 8 years ago

这样是不行的,你没看到我说的操作方法吗? 你发过来的我可以直接运行,我要的是你tika的读取结果!

hankcs commented 8 years ago

你把上面这么一串东西丢给我,我丢进去一看好好的呀

输出:

Query = text:专业 命中:1 test.docx , 0.25 软件工程【专业】是2002年国家教育部新增【专业】,随着计算机应用领域的不 断扩大及中国经济建设的不断发展,软件工程【专业】将成为一个新的热门专业。软 件工程【专业】以计算机科学与技术学科为基础,

然后我丢给你,有意义吗,问题还是没有解决啊

drmam commented 8 years ago

可是那个就是tika的输出结果呀

drmam commented 8 years ago

我刚才贴的输出结果,就是tika的输出。确实成功命中了一篇,不过高亮时候错误了。 所以高亮的那个没有输出。

hankcs commented 8 years ago

不是呀,贴上来的文本里面的控制符被去掉了啊

drmam commented 8 years ago

你等下,我找个tika的下载路径给你下,麻烦你了

hankcs commented 8 years ago

而且你的是Windows啊,控制符跟我不一样啊

hankcs commented 8 years ago

我高亮也好好的啊

drmam commented 8 years ago

http://download.csdn.net/detail/lixue198/8101777

drmam commented 8 years ago

你用这个试一下,看看会不会报错

hankcs commented 8 years ago

你为什么不用断点看变量呢?

drmam commented 8 years ago

你指的是那个地方

hankcs commented 8 years ago

String fileName=Parser("C:\Users\drmam\Desktop\test.docx");

请通过如下方式给我: 你必须在这句话上下一个断点,将fileName的值复制到剪切板,然后 String content = "粘贴一下";

drmam commented 8 years ago

3464bb30-9174-460a-9775-0288ac8441b7.pdf 实在不懂你的意思,不过我那个转换成pdf跟word中是不一样的

drmam commented 8 years ago

我打断点之后复制的值,不是跟我直接贴上来效果一样吗

hankcs commented 8 years ago

不是一样的,你再写一句 String content = "粘贴一下";

粘贴之后,ide会保留所有的不可见字符,罪魁祸首可能是不可见字符,你懂了吗?

hankcs commented 8 years ago

比如IDE会把回车自动转移成\r\t,你再把String content = "粘贴一下";这句代码整个发给我,我不就有了数据吗?

drmam commented 8 years ago

好的我先试下,因为我用的eclipse,所以不知道还可以那样。我先下载个ide。麻烦了

hankcs commented 8 years ago

我用tika在Linux下试了,没问题:

   软件工程专业是2002年国家教育部新增专业,随着计算机应用领域的不

断扩大及中国经济建设的不断发展,软件工程专业将成为一个新的热门专业。软 件工程专业以计算机科学与技术学科为基础,

Query = text:专业 命中:1 test.docx , 0.25 软件工程【专业】是2002年国家教育部新增【专业】,随着计算机应用领域的不 断扩大及中国经济建设的不断发展,软件工程【专业】将成为一个新的热门专业。软 件工程【专业】以计算机科学与技术学科为基础,

hankcs commented 8 years ago

我没有Windows,你必须照我建议的做,否则没法复现这个问题。

drmam commented 8 years ago

好的谢谢。 String fileName="软件工程专业是2002年国家教育部新增专业,\r随着计算机应用领域的不断扩大及中国经济建设的不断发展。"; 我加了"\r"就报了跟上面相同的错误

drmam commented 8 years ago

是不是因为系统不一样的问题

hankcs commented 8 years ago

奇怪,我加了\r也没有报错。只不过由于\r是回行首控制符,所以覆盖了控制台其他字符串而已,不是bug。我可能得找台Windows才能复现你的问题。

drmam commented 8 years ago

好的谢谢了

drmam commented 8 years ago

测试文件.pdf 你有试过使用pdf测试吗,偏移量会这样 Query = text:专业 命中:1 测试回测换行符 , 0.2795085

   软件工【程专】业是2002年国家教育部新【增专】业,随着计算机应用领域的

断扩大及中国经济建设的不断发展,软件工【程专】业将成为一个新的热【门专】业。

件工【程专】业以计算机科学与技术学科为基础,

drmam commented 8 years ago

非常感谢,你如果有工作就先忙吧,有时间再回答我。

hankcs commented 8 years ago

我在Windows上测试过了,你给的所有文件都测试通过,没有任何问题,截图如下: 2016-8-18 2-44-26