当前位置: 首页 > 知识库问答 >
问题:

使用Lucene TokenFilter将令牌分解为子令牌

蔺山
2023-03-14

我的程序需要索引与Lucene(4.10)非结构化文档,内容可以是任何。因此,我的自定义分析器使用ClassicTokenizer首先标记文档。

public class SymbolSplitterFilter extends TokenFilter {

private final CharTermAttribute termAtt;
private final PositionIncrementAttribute posIncAtt;
private final Stack<String> termStack;
private AttributeSource.State current;

public SymbolSplitterFilter(TokenStream in) {
    super(in);
    termStack = new Stack<>();
    termAtt = addAttribute(CharTermAttribute.class);
    posIncAtt = addAttribute(PositionIncrementAttribute.class);
}

@Override
public boolean incrementToken() throws IOException {
    if (!input.incrementToken()) {
        return false;
    }

    final String currentTerm = termAtt.toString();

    System.err.println("The original word was " + termAtt.toString());
    final int bufferLength = termAtt.length();

    if (bufferLength > 1 && currentTerm.indexOf("@") > 0) { // There must be sth more than just @
        // If this is the first pass we fill in the stack with the terms
        if (termStack.isEmpty()) {
            // We split the token abc@cd.com into abc and cd.com
            termStack.addAll(Arrays.asList(currentTerm.split("@")));
            // Now we have the constituting terms of the email in the stack
            System.err.println("The terms on the stacks are ");
            for (int i = 0; i < termStack.size(); i++) {
                System.err.println(termStack.get(i));
                /** The terms on the stacks are 
                * xyz
                * gmail.com
                */

            }

            // I am not sure it is the right place for this.
             current = captureState();

        } else {
            // This part seems to never be reached!
            // We add the constituents terms as tokens.
            String part = termStack.pop();
            System.err.println("Current part is " + part);
            restoreState(current);
            termAtt.setEmpty().append(part);                 
            posIncAtt.setPositionIncrement(0);
        }
    }

    System.err.println("In the end we have " + termAtt.toString());
    // In the end we have xyz@gmail.com
    return true;

}

但是,从来不处理堆栈。实际上,我不知道incrementToken方法是如何工作的,尽管我读了这个SO问题,也不知道它何时从tokenStream中处理给定的token。

最后,我要实现的目标是:对于xyz@gmail.com作为输入文本,我希望生成以下子标记:xyz@gmail.com xyz gmail.com

任何帮助都很感激,

共有1个答案

彭坚壁
2023-03-14

您的问题是,当堆栈第一次填充时,输入标记流已经耗尽。因此input.incrementToken()返回false。在递增输入之前,应先检查堆栈是否已填充。像这样:

public final class SymbolSplitterFilter extends TokenFilter {

private final CharTermAttribute termAtt;
private final PositionIncrementAttribute posIncAtt;
private final Stack<String> termStack;
private AttributeSource.State current;
private final TypeAttribute typeAtt;

public SymbolSplitterFilter(TokenStream in)
{
    super(in);
    termStack = new Stack<>();
    termAtt = addAttribute(CharTermAttribute.class);
    posIncAtt = addAttribute(PositionIncrementAttribute.class);
    typeAtt = addAttribute(TypeAttribute.class);
}

@Override
public boolean incrementToken() throws IOException
{
    if (!this.termStack.isEmpty()) {
        String part = termStack.pop();
        restoreState(current);
        termAtt.setEmpty().append(part);
        posIncAtt.setPositionIncrement(0);
        return true;
    } else if (!input.incrementToken()) {
        return false;
    } else {
        final String currentTerm = termAtt.toString();
        final int bufferLength = termAtt.length();

        if (bufferLength > 1 && currentTerm.indexOf("@") > 0) { // There must be sth more than just @
            if (termStack.isEmpty()) {
                termStack.addAll(Arrays.asList(currentTerm.split("@")));
                current = captureState();
            }
        }
        return true;

    }

}
}

注意,当测试显示生成的令牌时,您可能还希望纠正您的偏移量并更改令牌的顺序:

 public class SymbolSplitterFilterTest extends BaseTokenStreamTestCase {


@Test
public void testSomeMethod() throws IOException
{
    Analyzer analyzer = this.getAnalyzer();
    assertAnalyzesTo(analyzer, "hey xyz@example.com",
        new String[]{"hey", "xyz@example.com", "example.com", "xyz"},
        new int[]{0, 4, 4, 4},
        new int[]{3, 19, 19, 19},
        new String[]{"word", "word", "word", "word"},
        new int[]{1, 1, 0, 0}
        );
}

 private Analyzer getAnalyzer()
{
    return new Analyzer()
    {
        @Override
        protected Analyzer.TokenStreamComponents createComponents(String fieldName)
        {
            Tokenizer tokenizer = new MockTokenizer(MockTokenizer.WHITESPACE, false);
            SymbolSplitterFilter testFilter = new SymbolSplitterFilter(tokenizer);
            return new Analyzer.TokenStreamComponents(tokenizer, testFilter);
        }
    };
}

}
 类似资料:
  • 我想从Stormpath帖子中对JWT令牌和CSRF提出疑问,这些令牌和CSRF解释了将JWT存储在localStorage或Cookie中的优缺点。 [...] 如果您使用JS从cookie中读取值,这意味着您不能在cookie上设置Httponly标志,因此现在站点上的任何JS都可以读取它,从而使其与在localStorage中存储内容的安全级别完全相同。 我试图理解为什么他们建议将xsrfT

  • 我们如何才能让他们识别lexer规则?所有、和规则都可能与匹配。那么我在测试它的时候应该使用什么类型。 我的意思是: 一般来说,我想了解如何知道的类型?

  • Hangfire在发起一个取消任务请求或者终止任务时,为任务提供了取消令牌的支持,在前一种情况下,将自动放回队列的对头,允许Hangfire重新处理任务。 取消令牌通过 IJobCancellationToken 的接口暴露出来。当发起取消任务请求时,它通过 ThrowIfCancellationRequested 方法来抛出 OperationCanceledException : public

  • 我正在尝试使用 MSAL (1.0.304142221-alpha) 使用客户端凭据流获取微软图形 API 的令牌。我的代码看起来像这样: 第二行引发异常:“AADSTS70011:为输入参数'scope'提供的值无效。范围邮件读取无效。图形 API 引用似乎引用了“邮件.Read”作为所需的范围。 Azure AD中的应用程序是一个具有单个密钥的Web应用程序。应用程序具有Microsoft G

  • 问题内容: 我正在尝试使用OAuth 2.0访问Google的文档列表API 3.0,但是遇到401错误的麻烦。 用户接受后,我的代码如下: 然后,在最后一行-getFeed()-引发异常: 这是怎么回事?在静态主测试类上,它的工作原理很吸引人,但是当我在服务器上运行它时,此行不再起作用。任何想法? 解决了 需要使用GoogleOAuthHelper而不是直接使用GoogleOAuthParame

  • 目前访问类型处于联机状态。当我需要访问驱动器上的文件/文件夹时,我将浏览器重定向到Google URL并获得访问代码: 一切运转良好!但我只需要第一次重定向。 当我谷歌时,在google Drive API文档中,我发现我可以通过浏览器重定向获得刷新令牌,并将其保存在数据库中。(换句话说,我可以使用脱机访问)。 而且每次当我需要从google drive读取数据时,我使用刷新令牌获得访问令牌,而无