【问题标题】:Lucene 3.5 Custom PayloadsLucene 3.5 自定义负载
【发布时间】:2012-02-03 14:53:08
【问题描述】:

使用 Lucene 索引,我有一个看起来像这样的标准文档格式:

Name: John Doe 
Job: Plumber 
Hobby: Fishing

我的目标是将有效负载附加到作业字段,该字段将包含有关管道的其他信息,例如管道文章的维基百科链接。我不想将有效载荷放在其他任何地方。最初,我找到了一个示例,涵盖了我想做的事情,但它使用了 Lucene 2.2,并且没有更新来反映令牌流 api 中的更改。 经过更多研究,我想出了这个小怪物来为该领域构建自定义令牌流。

public static TokenStream tokenStream(final String fieldName, Reader reader, Analyzer analyzer, final String item) {
        final TokenStream ts = analyzer.tokenStream(fieldName, reader) ;
        TokenStream res = new TokenStream() {
            CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
            PayloadAttribute payAtt = addAttribute(PayloadAttribute.class);

            public boolean incrementToken() throws IOException {
                while(true) {
                    boolean hasNext = ts.incrementToken();
                    if(hasNext) {
                        termAtt.append("test");
                        payAtt.setPayload(new Payload(item.getBytes()));
                    }
                    return hasNext;
                }
            }

        };
        return res;
    } 

当我获取令牌流并迭代所有结果时,在将其添加到字段之前,我看到它成功地将术语和有效负载配对。在流上调用 reset() 后,我将其添加到文档字段并索引文档。但是,当我打印出文档并使用 Luke 查看索引时,我的自定义令牌流没有成功。字段名称正确显示,但令牌流中的术语值未出现,也未指示有效负载的成功附加。

这引出了两个问题。首先,我是否正确使用了令牌流,如果是,为什么在我将其添加到字段时它不进行令牌化?其次,如果我没有正确使用流,我是否需要编写自己的分析器。此示例是使用 Lucene 标准分析器拼凑而成的,以生成令牌流并写入文档。如果可能,我想避免编写自己的分析器,因为我只想将有效负载附加到一个字段!

编辑:

调用代码

TokenStream ts = tokenStream("field", new StringReader("value"), a, docValue);
        CharTermAttribute cta = ts.getAttribute(CharTermAttribute.class);
        PayloadAttribute payload = ts.getAttribute(PayloadAttribute.class);
        while(ts.incrementToken()) {
            System.out.println("Term = " + cta.toString());
            System.out.println("Payload = " + new String(payload.getPayload().getData()));

        }
        ts.reset();

【问题讨论】:

    标签: java lucene tokenize


    【解决方案1】:

    很难说为什么没有保存有效载荷,原因可能在于使用您提供的方法的代码。

    设置有效负载的最方便的方法是在TokenFilter 中——我认为采用这种方法会给您提供更简洁的代码,进而使您的场景正常工作。我认为在 Lucene 源代码中查看一些这种类型的过滤器是最能说明问题的,例如TokenOffsetPayloadTokenFilter。您可以在test for this class 中找到如何使用它的示例。

    还请考虑是否没有比在有效负载中存储这些超链接更好的地方。有效载荷有非常特殊的应用,例如根据它们在原始文档中的位置或格式、词性来提升某些术语......它们的主要目的是影响搜索的执行方式,因此它们通常是数值,有效地打包以减少索引大小。

    【讨论】:

    • 我将在今天晚些时候用调用代码更新帖子。最终数据可能不是超链接,我试图让这个概念发挥作用,而超链接是我在组装示例时首先想到的。 :)
    • 您是否研究过我建议的解决方案,即实施TokenFilter?它肯定会使代码更简洁,并且是在 Lucene 中做这些事情的最自然的方式。
    • 抱歉耽搁了,是的,我已经看过了。如果可以避免的话,我想暂时避免编写自己的分析器。但是,看起来这就是我必须要做的事情。
    【解决方案2】:

    我可能遗漏了一些东西,但是... 您不需要自定义标记器来将附加信息关联到 Lucene 文档。只是存储是一个未分析的领域。

    doc.Add(new Field("fname", "Joe", Field.Store.YES, Field.Index.ANALYZED));
    doc.Add(new Field("job", "Plumber", Field.Store.YES, Field.Index.ANALYZED));
    doc.Add(new Field("link","http://www.example.com", Field.Store.YES, Field.Index.NO));
    

    然后您可以像获取任何其他字段一样获取“链接”字段。

    此外,如果您确实需要一个自定义标记器,那么您肯定需要一个自定义分析器来实现它,用于索引构建和搜索。

    【讨论】:

    • 我搞砸了,问题是,它很慢。我不能利用 Postings 列表来检索一条信息。相反,我必须点击每一个文档,从索引中加载文档,然后获取字段。花费太多时间。
    猜你喜欢
    • 2014-12-05
    • 1970-01-01
    • 2016-03-08
    • 1970-01-01
    • 1970-01-01
    • 2011-12-17
    • 2017-03-19
    • 1970-01-01
    • 2016-09-12
    相关资源
    最近更新 更多