【问题标题】:Lucene search of two or more words not working on AndroidLucene 搜索两个或多个单词在 Android 上不起作用
【发布时间】:2014-06-20 05:40:55
【问题描述】:

我在 Android 上使用 Lucene 3.6.2。使用的代码和观察结果如下。

索引代码:

public void indexBookContent(Book book, File externalFilesDir) throws Exception {
    IndexWriter indexWriter = null;
    NIOFSDirectory directory = null;

    directory = new NIOFSDirectory(new File(externalFilesDir.getPath() + "/IndexFile", book.getBookId()));
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(LUCENE_36, new StandardAnalyzer(LUCENE_36));
    indexWriter = new IndexWriter(directory, indexWriterConfig);

    Document document = createFieldsForContent();

    String pageContent = Html.fromHtml(decryptedPage).toString();
    ((Field) document.getFieldable("content")).setValue(pageContent);
    ((Field) document.getFieldable("content")).setValue(pageContent);
    ((Field) document.getFieldable("content")).setValue(pageContent.toLowerCase());
}

private Document createFieldsForContent() {
    Document document = new Document();

    Field contentFieldLower = new Field("content", "", YES, NOT_ANALYZED);
    document.add(contentFieldLower);
    Field contentField = new Field("content", "", YES, ANALYZED);
    document.add(contentField);
    Field contentFieldNotAnalysed = new Field("content", "", YES, NOT_ANALYZED);
    document.add(contentFieldNotAnalysed);
    Field recordIdField = new Field("recordId", "", YES, ANALYZED);
    document.add(recordIdField);
    return document;
}

public JSONArray searchBook(String bookId, String searchText, File externalFieldsDir, String filter) throws Exception {
    List<SearchResultData> searchResults = null;
    NIOFSDirectory directory = null;
    IndexReader indexReader = null;
    IndexSearcher indexSearcher = null;

    directory = new NIOFSDirectory(new File(externalFieldsDir.getPath() + "/IndexFile", bookId));
    indexReader = IndexReader.open(directory);
    indexSearcher = new IndexSearcher(indexReader);

    Query finalQuery = constructSearchQuery(searchText, filter);

    TopScoreDocCollector collector = TopScoreDocCollector.create(100, false);
    indexSearcher.search(finalQuery, collector);
    ScoreDoc[] scoreDocs = collector.topDocs().scoreDocs;
}

private Query constructSearchQuery(String searchText, String filter) throws ParseException {
    QueryParser contentQueryParser = new QueryParser(LUCENE_36, "content", new StandardAnalyzer(LUCENE_36));
    contentQueryParser.setAllowLeadingWildcard(true);
    contentQueryParser.setLowercaseExpandedTerms(false);

    String wildCardSearchText = "*" + QueryParser.escape(searchText) + "*";

    // Query Parser used.
    Query contentQuery = contentQueryParser.parse(wildCardSearchText);
    return contentQueryParser.parse(wildCardSearchText);
}

我经历过这个:“Lucene: Multi-word phrases as search terms”,我的逻辑似乎没有什么不同。

我怀疑这些字段正在被覆盖。 另外,除了两个或多个单词支持的问题外,我需要与此代码一起使用的中文支持。

【问题讨论】:

  • 我似乎不明白你的确切问题是什么。就像您在链接中提到的那样,当您输入多个单词时不会返回正确的结果。您在哪个字段中搜索以及通过哪个查询,举个例子
  • 让我在这里陈述我的观察。单个单词的搜索效果很好,单个中文单词和特殊字符也是如此。但如果我搜索两个词,我没有得到任何结果。我将更新上面的代码以指定查询详细信息

标签: java android search lucene


【解决方案1】:

一个注释,在前面:

看到这样的搜索实现似乎有点奇怪。对所有可用字符串进行线性搜索似乎是一种过于复杂的方法。我不知道你到底需要完成什么,但我怀疑你会更好地对你的文本进行适当的分析,而不是对关键字分析的文本做一个双通配符,这将表现不佳,并且没有提供太多的灵活性搜索。


继续讨论更具体的问题:

您正在使用不同的分析方法多次分析同一字段中的相同内容。

Field contentFieldLower = new Field("content", "", YES, NOT_ANALYZED);
document.add(contentFieldLower);
Field contentField = new Field("content", "", YES, ANALYZED);
document.add(contentField);
Field contentFieldNotAnalysed = new Field("content", "", YES, NOT_ANALYZED);
document.add(contentFieldNotAnalysed);

相反,如果您确实需要所有这些分析方法都可用于搜索,您可能应该在不同的字段中对它们进行索引。一起搜索这些没有意义,所以它们不应该在同一个字段中。

那么你就有了这种模式:

Field contentField = new Field("content", "", YES, ANALYZED);
document.add(contentField);
//Somewhat later
((Field) document.getFieldable("content")).setValue(pageContent);

不要这样做,这没有意义。只需将您的内容传递给构造函数,并将其添加到您的文档中:

Field contentField = new Field("content", pageContent, YES, ANALYZED);
document.add(contentField);

特别是如果您选择继续在同一字段中以多种方式进行分析,则无法在不同的 Field 实现中找到一个(getFieldable 将始终返回第一个添加的)

这个查询:

String wildCardSearchText = "*" + QueryParser.escape(searchText) + "*";

正如您所提到的,不能很好地处理多个术语。它违反了 QueryParser 语法。你最终得到的是这样的:*two terms*,它将被搜索为:

field:*two field:terms*

这不会针对您的关键字字段生成任何匹配项(大概)。 QueryParser 根本不能很好地处理这种查询。您需要自己在这里构建一个通配符查询:

WildcardQuery query  = new WildcardQuery(new Term("field", "*two terms*"));

【讨论】:

  • 感谢您的来信。我使用 document.getFieldable 的原因是我正在使用相同的方法为“内容”以外的项目创建各种文档。我现在已经纠正了。效果很好。谢谢。
猜你喜欢
  • 1970-01-01
  • 2017-08-27
  • 1970-01-01
  • 1970-01-01
  • 2012-02-22
  • 1970-01-01
  • 1970-01-01
  • 2016-01-23
相关资源
最近更新 更多