【问题标题】:How to get records starting with a specific letter in Lucene如何在 Lucene 中获取以特定字母开头的记录
【发布时间】:2013-07-03 14:58:38
【问题描述】:

我有一个缓存的名单,我存储到 Lucene 数据结构中。我想找到名字以特定字母开头的人。

例如: 我的清单如下。我将它们存储到name 字段中。

foo bar
blabla foo
foo2 bar
test data

当我使用name:f* 搜索时,它会返回foo barfoo2 barblabla foo。它检查该字段中的每个单词并获得blabla foo。但是我需要让名字以f开头,它的第一个字母是f,而不是记录包含以f开头的单词,即使它们在句子的末尾。

有什么想法吗?

【问题讨论】:

  • 你可以看到我的帖子更新,并运行示例?

标签: java apache solr lucene


【解决方案1】:

建议使用不带标记的字段。
另外,不要使用通配符搜索,而是使用EdgeNGramTokenFilter,它会产生令牌,并且会比通配符搜索快得多,因为它会在索引时发生。

【讨论】:

    【解决方案2】:

    通配符搜索

    Lucene 支持在单个字词中(不是在短语查询中)进行单个和多个字符通配符搜索。

    要执行单个字符通配符搜索,请使用“?”符号。

    要执行多字符通配符搜索,请使用“*”符号。

    单字符通配符搜索查找与替换的单字符匹配的术语。例如,要搜索“text”或“test”,您可以使用搜索:

    te?t 多字符通配符搜索查找 0 个或多个字符。例如,要搜索 test、tests 或 tester,您可以使用搜索:

    测试*

    示例,使用正则表达式

    RegexQuery query = new RegexQuery(newTerm("^a.*$"));
    
    
    query.setRegexImplementation(new JavaUtilRegexCapabilities());
    
    return searcher.search(query, null, 1000).totalHits;
    

    http://lucene.apache.org/core/4_3_1/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#package_description

    示例代码:

            BasicConfigurator.configure();
    
            Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_CURRENT);
    
            // Store the index in memory:
            Directory directory = new RAMDirectory();
            // To store an index on disk, use this instead:
            // Directory directory = FSDirectory.open(new
            // File("./lucene/data"));
            IndexWriterConfig config = new IndexWriterConfig(
                    Version.LUCENE_CURRENT, analyzer);
            IndexWriter iwriter;
    
            iwriter = new IndexWriter(directory, config);
    
            String[] words = { "Olimpia", "Cerro", "Olimpo", "Libertad",
                    "Nacional", "Sol", "O'higgins", "Sao Paulo",
                    "Oriente Petrolero", "Barrio Obrero", "B. Obrero" };
    
            for (String word : words) {
                Document doc = new Document();
                String text = word;
                doc.add(new Field("name", text, Field.Store.YES,
                        Field.Index.NOT_ANALYZED));
    
                // ,Field.Store.NO, Field.Index.NOT_ANALYZED
                iwriter.addDocument(doc);
            }
    
            iwriter.close();
    
            // Now search the index:
    
            logger.info("HelloLucene.main: query2 -----------");
    
            DirectoryReader ireader2 = DirectoryReader.open(directory);
            IndexSearcher isearcher2 = new IndexSearcher(ireader2);
    
            logger.info("HelloLucene.main: query2 -----------");
            RegexQuery query2 = new RegexQuery(new Term("name", "O.*"));
            query2.setRegexImplementation(new JavaUtilRegexCapabilities(
                    JavaUtilRegexCapabilities.FLAG_CASE_INSENSITIVE));
    
            ScoreDoc[] hits2 = isearcher2.search(query2, null, 1000).scoreDocs;
            for (int i = 0; i < hits2.length; i++) {
                Document hitDoc = isearcher2.doc(hits2[i].doc);
                logger.info("HelloLucene.main: starting with O = "
                        + hitDoc.get("name"));
    
            }
    

    【讨论】:

    • 我已经知道了。我想搜索首字母为“A”的句子。它应该找到“Alice Run”而不是“Run Alice”。
    • 可以设置使用正则表达式,例如regexQueryNrHits("^a.*$",newJavaUtilRegexCapabilies())
    • 你指的是this question吗? regexQueryNrHits 几乎不是标准的 lucene 库的东西......无论如何,据我所知,Lucene RegexpQuery 不支持 ^$ 或任何其他样式的行首/行尾语法。
    【解决方案3】:

    默认情况下,这就是 Lucene 的运行方式。如果将字段标记为术语,并且您搜索出现在字段中任何位置的术语。对于大文本文档,这绝对有意义,因为您可能永远不想只从大量文本的开头进行搜索。

    如果您希望能够以文字字符串而不是一组标记化的术语进行搜索,最好的解决方案是以支持该功能的方式对其进行索引。 Solr.StrField 是典型的类型选择,而不是 TextField

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多