【问题标题】:Lucene indexing - lots of docs/phrasesLucene 索引 - 大量文档/短语
【发布时间】:2013-10-03 08:15:30
【问题描述】:

我应该使用什么方法来索引以下文件集。

每个文件包含大约 500k 行字符 (400MB) - 字符不是单词,它们是,可以说是随机字符,没有空格。

我需要能够找到包含给定 12 个字符的字符串的每一行,例如:

行: AXXXXXXXXXXXXJJJJKJIDJUD....等多达 200 个字符

有趣的部分:XXXXXXXXXXXX

在搜索时,我只对字符 1-13 感兴趣(所以 XXXXXXXXXXXX)。搜索后,我希望能够读取包含 XXXXXXXXXXXX 的行,而无需遍历文件。

我写了以下 poc(问题简化:

索引:

 while ( (line = br.readLine()) != null ) {
        doc = new Document();
        Field fileNameField = new StringField(FILE_NAME, file.getName(), Field.Store.YES);
        doc.add(fileNameField);
        Field characterOffset = new IntField(CHARACTER_OFFSET, charsRead, Field.Store.YES);
        doc.add(characterOffset);
        String id = "";
        try {
            id = line.substring(1, 13);
            doc.add(new TextField(CONTENTS, id, Field.Store.YES));
            writer.addDocument(doc);
        } catch ( IndexOutOfBoundsException ior ) {
            //cut off for sake of question
        } finally {
            //simplified snipped for sake of question. characterOffset is amount of chars to skip which reading a file (ultimately bytes read)
             charsRead += line.length() + 2;

        }
    }

搜索:

RegexpQuery q = new RegexpQuery(new Term(CONTENTS, id), RegExp.NONE); //cause id can be a regexp concernign 12char string

TopDocs results = searcher.search(q, Integer.MAX_VALUE);
ScoreDoc[] hits = results.scoreDocs;
int numTotalHits = results.totalHits;
Map<String, Set<Integer>> fileToOffsets = new HashMap<String, Set<Integer>>();

for ( int i = 0; i < numTotalHits; i++ ) {
    Document doc = searcher.doc(hits[i].doc);
    String fileName = doc.get(FILE_NAME);
    if ( fileName != null ) {
        String foundIds = doc.get(CONTENTS);
        Set<Integer> offsets = fileToOffsets.get(fileName);
        if ( offsets == null ) {
            offsets = new HashSet<Integer>();
            fileToOffsets.put(fileName, offsets);
        }
        String offset = doc.get(CHARACTER_OFFSET);
        offsets.add(Integer.parseInt(offset));
    }
}

这种方法的问题在于,它将每行创建一个文档。

您能否给我一些提示,如何使用 lucene 解决这个问题,以及 lucene 是否可以解决这个问题?

【问题讨论】:

    标签: java lucene indexing


    【解决方案1】:

    不要为每次迭代添加一个新文档,而是使用相同的文档并继续向其添加具有相同名称的字段,例如:

    Document doc = new Document();
    Field fileNameField = new StringField(FILE_NAME, file.getName(), Field.Store.YES);
    doc.add(fileNameField);
    String id;
    while ( (line = br.readLine()) != null ) {
        id = "";
        try {
            id = line.substring(1, 13);
            doc.add(new TextField(CONTENTS, id, Field.Store.YES));
            //What is this (characteroffset) field for?
            Field characterOffset = new IntField(CHARACTER_OFFSET, bytesRead, Field.Store.YES);
            doc.add(characterOffset);
        } catch ( IndexOutOfBoundsException ior ) {
            //cut off
        } finally {
            if ( "".equals(line) ) {
                bytesRead += 1;
            } else {
                bytesRead += line.length() + 2;
            }
        }
    }
    writer.addDocument(doc);
    

    这会将每一行的 id 作为新术语添加到同一字段中。相同的查询应该会继续工作。

    不过,我不确定您如何使用CharacterOffset 字段。与 id 一样,每个值都将作为另一个术语附加到字段的末尾。它不会直接与特定术语相关联,除了人们会假设在该字段中存在相同数量的标记。如果您需要检索特定行,而不是整个文件的内容,您当前的逐行索引方法可能是最合理的。

    【讨论】:

    • characterOffset 是读取文件时要跳过的字符数 - 这是从文件中获取所需行的有效方法。 characterOffset 应该与 id 一起使用,因为它标识文件中的行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-21
    相关资源
    最近更新 更多