文本检索 关键词检索和
问候,
介绍在我们开始设计和实现文本生成器类之前,我想
提Prometheuzz的回复:他有整个圣经的荷兰语版本
可用,包括那些奇特的书。 我下载了整个shebang,
入侵了我的King James文字处理器,现在我有两本圣经可供使用:
英文的“ King James”版本和荷兰的“ Staten Vertaling”版本。
荷兰语版本甚至比国王詹姆斯版还大,所以:-P
感谢Prometheuzz提供的那段有价值的文字; 我真的很感激。
在我已故的邻居中,荷兰语版本的矛盾较少(阅读:否)
德克的版本到处都是一团糟。 大部分原始解析文本麻烦
发生在Dirk的版本中。 只是进行了一些重写和快速黑客攻击
足以处理Prometheuzz提供的荷兰语版本。
LibraryBuilder我们有工作要做:这又是LibraryBuilder界面:
public interface LibraryBuilder {
public void preProcess();
public void postProcess();
public void setTitle(String title);
public void buildGroup(String group);
public void buildParagraph(String book, String chapter, int para, String text) throws IOException;
public Library build();
}
AbstractBuilder类实现了所有此接口,并留下了一些
特定构建器将实现的抽象受保护方法,例如
KJBuilder(用于King James圣经版本)和SVBuilder(用于
Staten Vertaling版本)。
AbstractBuilder本身并不能完成所有工作,即它委托了很多
对于较小和较简单的建造者的工作。
这是所有这些的简单构建器:StringsBuilder:
class StringsBuilder extends ArrayList<String> {
private static final long serialVersionUID = 4709552086518644567L;
String[] build() { return this.toArray(new String[size()]); }
}
它只是List <String>接口的一个实现,可以构建
给我们一个String []。 这就是全部。 请记住,图书馆本身只是
对整个文本使用一堆数组。 数组无法调整大小; 那是
我之所以喜欢构建器的原因之一,是那些操作更灵活但体积更大的建筑
数据结构(类),而最后生成所有数组。
这是另一个简单的构建器; 它建立了一个部分:
package text.builders;
import text.library.Section;
class SectionBuilder {
private String name;
private int index;
private int total;
SectionBuilder(String name, int index) {
this.name = name;
this.index= index;
}
void setTotal(int end) { this.total= end-index; }
String getName() { return name; }
Section build() { return new Section(name, index, total); }
}
节可以是组中的节,书或章。
“索引”
成员指的是团体,书籍或
章节。 “总数”成员是该特定部分中的部分总数
数组。 另请参阅本文的上一部分,以获取各节的示例。
上面的代码可以构建一个Section。 下一个小的构建器将构建一个数组
我们的部分; 这里是:
class SectionsBuilder extends ArrayList<SectionBuilder> {
private static final long serialVersionUID = 1476840322184839715L;
boolean addSection(String name, int index, boolean add) {
int n= size();
SectionBuilder s= (n == 0)?null:get(n-1);
if (add= (add || s == null || !s.getName().equals(name))) {
add(new SectionBuilder(name, index));
if (s != null) s.setTotal(index);
}
return add;
}
void postProcess(int total) {
if (size() > 0)
get(size()-1).setTotal(total);
}
Section[] build() {
int n= size();
Section[] sections= new Section[n];
for (int i= 0; i < n; i++)
sections[i]= this.get(i).build();
return sections;
}
}
SectionsBuilder是SectionBuilders的列表(不是不同的复数)。
当一个新的部分即将开始时,它会计算出多少个“事物”
在上一节中。 参见addSection()方法。 布尔值
无论如何,“ add”变量(如果为true)都会强制构建新的Section。
当此变量为false时,如果名称为
当前部分与前一个部分不同,或者
建造是所有这些的第一部分。
实际上,此构建器根本不跟踪Sections:它处理
SectionBuilders。 此构建器的build()方法将构建实际的Sections:
它在其列表中的每个SectionBuilder上调用build()方法,该方法依次
每个建立一个科。
间奏曲让我们在此处暂停一分钟:我们可以构建单个Sections(使用
SectionBuilder),我们可以构建Sections的数组(使用SectionsBuilder)。
我们还可以使用StringsBuilder构建字符串数组。
但是我们还需要更多:我们需要知道单词出现在哪些段落中。 其他
单词(原文如此),我们需要在单个单词和列表中的索引列表之间建立映射
段落列表。 单个段落是代表以下内容的索引的字符串
再次是单个单词和标点符号。 (请参阅上一篇文章
有关如何压缩段落的部分)。
还有更多工作要做...
更多建设者这是一个WordBuilder; 它会跟踪其中一个单词的段落编号
发生。 不过,它不在乎哪个词。 已经找到了某个地方
其他。 它确实知道它是整个文本中的第“ index”个词。 这是
实现:
class WordBuilder {
private int index;
private List<Integer> paragraphs= new ArrayList<Integer>();
WordBuilder(int paragraph) {
this.index= paragraph;
}
int getIndex() { return index; }
void addParagraph(int paragraph) { paragraphs.add(paragraph); }
int[] build() {
int n= paragraphs.size();
int array[]= new int[n];
for (int i= 0; i < n; i++) array[i]= paragraphs.get(i);
return array;
}
}
它基本上会跟踪此特定段落的列表编号列表
单词出现,它可以建立一个整数数组,这些段落的索引
在这个词再次出现。 火箭科学不是特别重要。
最后一个生成器将单词映射到WordBuilders。 毫不奇怪
该生成器名为WordMapBuilder; 这里是:
class WordMapBuilder extends HashMap<String, WordBuilder> {
private static final long serialVersionUID = -5282145470567550534L;
WordMap build() {
WordMap map= new WordMap();
for (Map.Entry<String, WordBuilder> entry : entrySet())
map.put(entry.getKey(), entry.getValue().build());
return map;
}
}
它将一个单词(一个字符串)映射到一个WordBuilder(见上文),它可以产生
WordMap。 稍后我们会看到它,但我想您可以猜测是什么:它
将字符串(单词)映射到Integer [],这是其中
单词出现。
抽象生成器现在我们有了实现LibraryBuilder的组成部分,让我们来看看
此实现的全部意义。 该类是一个抽象类,因为
它为扩展类留下了一些简单的方法:
protected abstract String clean(String book, String chapter,
int paragraph, String text);
protected abstract Collection<String> getNoise();
第一种方法应该清除段落文本。
大部分是
已经以一般方式清理了,但是特定的构建器可能需要清理
文字甚至更多。
在德克(Dirk)的国王詹姆斯(King James)版本中,某些词带有花括号,而另一些则带有
大括号周围。 我不需要那些花括号,所以我的KJBuilder的clean()
方法实现如下所示:
protected String clean(String book, String chapter,
int paragraph, String text) {
text= text.replaceAll("[({\\[\\]})]", "");
return text.replaceAll("[^\\x20-\\x7e]", "");
}
我通过删除所有非7位ASCII字符来进一步清理文本
文字中的内容(还记得第一篇文章顶部带有点的那些“ y”吗?
这摆脱了他们)。
第二种方法应该返回一个不是
应该被索引。 想想诸如“ the”,“ a”,“ is”之类的词。
AbstractBuilder完成了所有工作,只需要知道*哪些词是
应该从WordMap中排除(请参见上文)。
这是KJBuilder(扩展AbstractBuilder)返回其干扰词的方式:
private static final Set<String> noise= new HashSet<String>();
static {
noise.addAll(Arrays.asList(new String[] {
"O", "s",
"The", "the",
"A", "a", "An", "an",
"Of", "of", "By", "by", "On", "on",
"Am", "am", "Are", "are", "Is", "is", "Be", "be",
"Had", "had", "Has", "has", "Have", "have",
"At", "at", "As", "as", "In", "in",
"Do", "do",
}));
}
protected Collection<String> getNoise() {
return noise;
}
HashSet是一个Set,而Set是一个Collection。
Arrays.asList()方法可以
从数组中构建一个列表,集合可以接受一个列表,该列表也是
集合作为构造函数参数,最终由返回
getNoise()方法。
今天已经足够打字了。 我去给自己喝杯咖啡。 我希望看到
您将在本文下面的下一部分中找到您。
亲切的问候,
乔斯
B部分翻译自: https://bytes.com/topic/java/insights/681150-text-retrieval-systems-3a-library-builder
文本检索 关键词检索和