【问题标题】:Add field in Lucene document在 Lucene 文档中添加字段
【发布时间】:2012-12-21 22:42:00
【问题描述】:

您好,我有一个 32mb 的文件。它是一个简单的字典文件,编码为 1250,其中包含 280 万行。每一行只有一个唯一的单词:

cat
dog
god
...

我想使用 Lucene 搜索特定单词字典中的每个字谜。例如:

我想搜索单词 dog 的每个字谜,lucene 应该搜索我的字典并返回 doggod。在我的 webapp 中,我有一个 Word 实体:

public class Word {
    private Long id;
    private String word;
    private String baseLetters;
    private String definition;
}

并且 baseLetters 是按字母顺序排序的变量,用于搜索此类字谜[神和狗词将具有相同的 baseLetters:dgo]。我在不同的服务中使用这个 baseLetters 变量成功地从我的数据库中搜索了这样的字谜,但是我在创建字典文件的索引时遇到了问题。我知道我必须添加到字段:

word 和 baseLetters,但我不知道该怎么做 :( 有人可以告诉我一些实现这个目标的方向吗?

目前我只有这样的东西:

public class DictionaryIndexer {

private static final Logger logger = LoggerFactory.getLogger(DictionaryIndexer.class);

@Value("${dictionary.path}")
private String dictionaryPath;

@Value("${lucene.search.indexDir}")
private String indexPath;

public void createIndex() throws CorruptIndexException, LockObtainFailedException {
    try {
        IndexWriter indexWriter = getLuceneIndexer();
        createDocument();           
    } catch (IOException e) {
        logger.error(e.getMessage(), e);
    }       
 }

private IndexWriter getLuceneIndexer() throws CorruptIndexException, LockObtainFailedException, IOException {
    StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_36);
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, analyzer);
    indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);
    Directory directory = new SimpleFSDirectory(new File(indexPath));
    return new IndexWriter(directory, indexWriterConfig);
}

private void createDocument() throws FileNotFoundException {
    File sjp = new File(dictionaryPath);
    Reader reader = new FileReader(sjp);

    Document dictionary = new Document();
    dictionary.add(new Field("word", reader));
}

}

PS:还有一个问题。如果我在 Spring 中将 DocumentIndexer 注册为 bean,每次我重新部署我的 webapp 时,索引是否会创建/附加?未来的 DictionarySearcher 也会如此吗?

【问题讨论】:

  • Lucene 不知道文件,它需要对字符串进行索引。因此,您需要逐行读取文件并每行创建一个“文档”对象,每个对象有两个字段。此外,每个文档都需要添加到索引编写器中。

标签: java spring lucene


【解决方案1】:

Lucene 不是最好的工具,因为你不是在做搜索:你是在做查找。所有实际工作都发生在“索引器”中,然后您只需存储所有工作的结果。在任何哈希类型的存储机制中查找都可以是 O(1)。

这是您的索引器应该执行的操作:

  1. 将整个字典读入一个简单的结构,如SortedSetString[]
  2. 创建一个空的HashMap<String,List<String>>(可能大小相同,以提高性能)用于存储结果
  3. 按字母顺序遍历字典(实际上任何顺序都可以,只要确保您点击了所有条目)
    1. 对单词中的字母进行排序
    2. 在您的存储集合中查找已排序的字母
    3. 如果查找成功,将当前单词添加到列表中;否则,创建一个包含该单词的新列表并将其放入存储Map
  4. 如果以后需要这张地图,把地图存到磁盘上;否则,请记住它
  5. 丢弃字典

以下是您的查找过程应该执行的操作:

  1. 对示例单词中的字母进行排序
  2. 在您的存储集合中查找已排序的字母
  3. 打印从查找返回的List(或 null),注意省略输出中的示例词

如果您想节省堆空间,请考虑使用DAWG。你会发现你可以用几百千字节而不是 32MiB 来表示整个英语单词词典。我将把它作为练习留给读者。

祝你的家庭作业好运。

【讨论】:

  • 您好,感谢您的解决方案。起初我想说这不是作业,而是我项目中的现实问题,我只是考虑哪种方法更好地解决它。这个字典文件不是我的,只是来自 Internet 的资源。我想用KISS原理解决这个问题,我认为我可以使用Lucene进行搜索或查找。你真的认为你的解决方案比 Lucene 更有优势吗?这种查找将是我项目的基本功能,并将被广泛使用。
  • Lucene 的强大之处在于从复杂的基于文本的数据创建复杂的索引。您的数据并不复杂(单个单词),您的索引也不复杂(这些单词的字谜)。您当然可以使用 Lucene,但它更适合您想要的用途。您想对单个字段进行精确匹配。您也可以使用 RDBMS,但您已经知道这很愚蠢……如果您的要求已在您的问题中得到充分体现,那么使用 Lucene 也是愚蠢的。
【解决方案2】:

函数createDocument()应该是

private void createDocument() throws FileNotFoundException {
    File sjp = new File(dictionaryPath);
    BufferedReader reader = new BufferedReader(new FileReader(sjp));

    String readLine = null;
    while((readLine = reader.readLine() != null)) {
        readLine = readLine.trim();
        Document dictionary = new Document();
        dictionary.add(new Field("word", readLine));
        // toAnagram methods sorts the letters in the word. Also makes it
        // case insensitive.
        dictionary.add(new Field("anagram", toAnagram(readLine)));
        indexWriter.addDocument(dictionary);
    }
}

如果您将 Lucene 用于很多功能,请考虑使用 Apache Solr,这是一个基于 Lucene 构建的搜索平台。

您还可以为每个字谜组仅使用一个条目来建模您的索引。

{"anagram" : "scare", "words":["cares", "acres"]}
{"anagram" : "shoes", "words":["hoses"]}
{"anagram" : "spore", "words":["pores", "prose", "ropes"]}

这需要在处理您的字典文件时更新索引中的现有文档。在这种情况下,Solr 将有助于使用更高级别的 API。例如,IndexWriter does not support updating documents。 Solr 支持更新。

这样的索引将为每个字谜搜索提供一个结果文档。

希望对你有帮助。

【讨论】:

  • 非常感谢。我只是想了解 Lucene,所以我选择了您的解决方案。我的项目处于早期阶段,很有可能在未来我会为 Apache Lucene 提供更多功能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多