Lucene 索引是否有助于加快计数出现次数?
Will Lucene index help speed up to count occurrence?
我有一个大文本文件,我想从中计算已知短语的出现次数。我目前将整个文本文件逐行读取到内存中,并使用 'find' 函数检查文本文件中是否存在特定短语:
found = txt.find(phrase)
这对于大文件来说非常慢。为所有可能的短语建立索引并将它们存储在字典中会有所帮助,但问题是自己创建所有有意义的短语具有挑战性。我知道 Lucene 搜索引擎支持短语搜索。在使用 Lucene 为文本集创建索引时,我是否需要想出自己的标记化方法,特别是为了我上面的短语搜索目的?或者 Lucene 有一种有效的方法可以自动为所有可能的短语创建索引,而无需我担心如何创建短语?
我的主要目的是找到一种计算大文本中出现次数的好方法。
总结:Lucene 会负责将更高的匹配分数分配给与您的输入短语更匹配的索引文本,而您不必 "create all meaningful phrases" 自己。
从简单开始
我建议你从一个基本的 Lucene 分析器开始,看看它有什么效果。它很有可能会满足您的需求。
如果这不能给您满意的结果,那么您当然可以进一步调查 specific/targeted analyzers/tokenizers/filters(例如,如果您需要分析非拉丁字符集)。
如果不更详细地查看源数据和短语匹配要求,很难更具体。
但是,话虽如此,这里有两个示例(我假设您基本熟悉如何创建 Lucene 索引,然后对其进行查询)。
所有代码均基于 Lucene 8.4。
警告 - 我不熟悉 Lucene 的 Python 实现。因此,抱歉,我的示例在 Java 中 - 而不是 Python(因为您的问题已被标记)。我想这些概念在某种程度上是可以翻译的。很抱歉,如果这对您来说是个阻碍。
基本的多用途分析仪
这是一个基本的分析器——使用 Lucene "service provider interface" 语法和 CustomAnalyzer:
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.custom.CustomAnalyzer;
...
Analyzer analyzer = CustomAnalyzer.builder()
.withTokenizer("icu")
.addTokenFilter("lowercase")
.addTokenFilter("asciiFolding")
.build();
上述分析器使用 Unicode 空格规则对您的输入文本进行标记化,如编码到 ICU libraries 中一样。然后它标准化为小写字母,并映射 accents/diacritics/etc。到它们的 ASCII 等价物。
使用带状疱疹的示例
如果上述方法被证明不能满足您的特定短语匹配需求(即误报得分过高),那么您可以尝试的一种技术是使用带状疱疹作为标记。阅读更多关于带状疱疹的信息 here(Elasticsearch 有很棒的文档)。
这是一个使用 shingles 并使用 more "traditional" 语法的示例分析器:
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.LowerCaseFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.standard.StandardTokenizer;
import org.apache.lucene.analysis.StopwordAnalyzerBase;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter;
import org.apache.lucene.analysis.shingle.ShingleFilter;
...
StopwordAnalyzerBase.TokenStreamComponents createComponents(String fieldName) {
final Tokenizer source = new StandardTokenizer();
TokenStream tokenStream = source;
tokenStream = new LowerCaseFilter(tokenStream);
tokenStream = new ASCIIFoldingFilter(tokenStream);
// default shingle size is 2:
tokenStream = new ShingleFilter(tokenStream);
return new Analyzer.TokenStreamComponents(source, tokenStream);
}
在此示例中,默认的 shingle 大小为 2(每个 shingle 两个字)- 这是一个很好的起点。
终于...
即使您认为这是一次性练习,以 repeatable/automated 方式构建一些 Lucene 索引可能仍然值得麻烦(这可能需要一段时间,具体取决于数量)你拥有的数据)。
那样的话,运行你的一组已知短语对照索引会很快,看看每个索引的效果如何。
我故意不说你的终极objective(来计算出现次数”),因为那部分应该相对简单,假设您真的想找到已知短语的精确匹配。有可能我误解了你的问题 - 但在高层次上我认为这就是你所需要的。
我有一个大文本文件,我想从中计算已知短语的出现次数。我目前将整个文本文件逐行读取到内存中,并使用 'find' 函数检查文本文件中是否存在特定短语:
found = txt.find(phrase)
这对于大文件来说非常慢。为所有可能的短语建立索引并将它们存储在字典中会有所帮助,但问题是自己创建所有有意义的短语具有挑战性。我知道 Lucene 搜索引擎支持短语搜索。在使用 Lucene 为文本集创建索引时,我是否需要想出自己的标记化方法,特别是为了我上面的短语搜索目的?或者 Lucene 有一种有效的方法可以自动为所有可能的短语创建索引,而无需我担心如何创建短语?
我的主要目的是找到一种计算大文本中出现次数的好方法。
总结:Lucene 会负责将更高的匹配分数分配给与您的输入短语更匹配的索引文本,而您不必 "create all meaningful phrases" 自己。
从简单开始
我建议你从一个基本的 Lucene 分析器开始,看看它有什么效果。它很有可能会满足您的需求。
如果这不能给您满意的结果,那么您当然可以进一步调查 specific/targeted analyzers/tokenizers/filters(例如,如果您需要分析非拉丁字符集)。
如果不更详细地查看源数据和短语匹配要求,很难更具体。
但是,话虽如此,这里有两个示例(我假设您基本熟悉如何创建 Lucene 索引,然后对其进行查询)。
所有代码均基于 Lucene 8.4。
警告 - 我不熟悉 Lucene 的 Python 实现。因此,抱歉,我的示例在 Java 中 - 而不是 Python(因为您的问题已被标记)。我想这些概念在某种程度上是可以翻译的。很抱歉,如果这对您来说是个阻碍。
基本的多用途分析仪
这是一个基本的分析器——使用 Lucene "service provider interface" 语法和 CustomAnalyzer:
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.custom.CustomAnalyzer;
...
Analyzer analyzer = CustomAnalyzer.builder()
.withTokenizer("icu")
.addTokenFilter("lowercase")
.addTokenFilter("asciiFolding")
.build();
上述分析器使用 Unicode 空格规则对您的输入文本进行标记化,如编码到 ICU libraries 中一样。然后它标准化为小写字母,并映射 accents/diacritics/etc。到它们的 ASCII 等价物。
使用带状疱疹的示例
如果上述方法被证明不能满足您的特定短语匹配需求(即误报得分过高),那么您可以尝试的一种技术是使用带状疱疹作为标记。阅读更多关于带状疱疹的信息 here(Elasticsearch 有很棒的文档)。
这是一个使用 shingles 并使用 more "traditional" 语法的示例分析器:
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.LowerCaseFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.standard.StandardTokenizer;
import org.apache.lucene.analysis.StopwordAnalyzerBase;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter;
import org.apache.lucene.analysis.shingle.ShingleFilter;
...
StopwordAnalyzerBase.TokenStreamComponents createComponents(String fieldName) {
final Tokenizer source = new StandardTokenizer();
TokenStream tokenStream = source;
tokenStream = new LowerCaseFilter(tokenStream);
tokenStream = new ASCIIFoldingFilter(tokenStream);
// default shingle size is 2:
tokenStream = new ShingleFilter(tokenStream);
return new Analyzer.TokenStreamComponents(source, tokenStream);
}
在此示例中,默认的 shingle 大小为 2(每个 shingle 两个字)- 这是一个很好的起点。
终于...
即使您认为这是一次性练习,以 repeatable/automated 方式构建一些 Lucene 索引可能仍然值得麻烦(这可能需要一段时间,具体取决于数量)你拥有的数据)。
那样的话,运行你的一组已知短语对照索引会很快,看看每个索引的效果如何。
我故意不说你的终极objective(来计算出现次数”),因为那部分应该相对简单,假设您真的想找到已知短语的精确匹配。有可能我误解了你的问题 - 但在高层次上我认为这就是你所需要的。