- 浏览: 928154 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (445)
- 备忘 (0)
- java基础 (28)
- jsp (15)
- css (4)
- javascript (30)
- struts (7)
- servlet (2)
- struts2 (7)
- jdbc (16)
- hibernate (22)
- ibatis (0)
- jpa (1)
- spring (17)
- spring定时任务 (8)
- 整合开发 (12)
- JavaArticle (0)
- php (6)
- velocity (2)
- mysql (19)
- sqlserver (52)
- oracle (23)
- lucene (49)
- ajax (13)
- dwr (5)
- JFreeChart (1)
- service (14)
- tools (18)
- c#基础 (20)
- 程序安全 (0)
- 学习网站 (1)
- 社会需求 (2)
- flash (1)
- 流媒体 (1)
- java_code (1)
- htmlparser (1)
- 速动画教程 (5)
- 设计模式 (1)
- xml操作 (2)
- uml操作 (4)
- 测试 (1)
- linux (8)
- 版本控制 (4)
- 服务器 (12)
- 安全 (6)
- 美工 (2)
最新评论
-
Zhang_amao:
我想问一下, 你用的lucene版本和highligher的版 ...
使用Lucene的Highlighter实现文件摘要的自动提取 -
wangmengfanwangzhi:
博主,你的QQ是什么啊?有关于lucene的问题想要请教啊~~ ...
Lucene下载及测试 -
cutesunshineriver:
讲得很好,理解起来很顺,对个人学习的帮助性很大,谢谢博主。
velocity入门一 -
libin2722:
我这里有一个任务调度,在晚上3点时候会自动将数据库中某表的数据 ...
Lucene-2.2.0 源代码阅读学习(16) -
greatwqs:
java -cp $JVM_ARGS $classpath ...
java的cp命令
如果在初始化一个IndexWriter索引器的时候,指定 useCompoundFile =false,则在指定的索引目录中生成的索引文件就不是.cfs复合索引文件。
通过这种方式生成的索引文件,它的不同格式表明了它锁存储的关于索引的不同内容。
至少,明确了在建立索引过程中,经过加工处理的数据究竟去向如何,能够加深对Lucene索引过程的理解。
通过在文章 Lucene-2.2.0 源代码阅读学习(4) 中的那个例子,可以运行主函数,观察到索引目录中生成了大量的不同扩展名的索引文件,当然它们不是复合索引文件,如图所示:
这些不同扩展名的索引文件都是有一定的含义的。
如果只是根据这些文件名来说明它的含义,让人感觉很抽象,那么就通过代码来看,它们到底都存储了一些什么内容。
_N.fnm文件
当向一个IndexWriter索引器实例添加Document的时候,调用了IndexWroter的addDocument()方法,在方法的内部调用如下:
buildSingleDocSegment() —> String segmentName = newRamSegmentName();
这时,调用newRamSegmentName()方法生成了一个segment的名称,形如_ram_N,这里N为36进制数。
这个新生成的segmentName作为参数值传递到DocumentWriter类的addDocument()方法中:
dw.addDocument(segmentName, doc);
在DocumentWriter类中,这个segmentName依然是_ram_N形式的,再次作为参数值传递:
fieldInfos.write(directory, segment + ".fnm");
这个时候,就要发生变化了,在FieldInfos类的第一个write()方法中输出System.out.println(name);,结果如下所示:
_ram_0.fnm
_ram_1.fnm
_ram_2.fnm
_ram_3.fnm
_ram_4.fnm
_ram_5.fnm
_ram_6.fnm
_ram_7.fnm
_ram_8.fnm
_ram_9.fnm
_0.fnm
_ram_a.fnm
_ram_b.fnm
_ram_c.fnm
_ram_d.fnm
_ram_e.fnm
_ram_f.fnm
_ram_g.fnm
_ram_h.fnm
_ram_i.fnm
_ram_j.fnm
_1.fnm
_ram_k.fnm
……
而且,可以从Directory看出究竟在这个过程中发生了怎样的切换过程,在FieldInfos类的第一个write()方法中执行:
if(d instanceof FSDirectory){
System.out.println("FSDirectory");
}
else{
System.out.println("----RAMDirectory");
}
输出结果如下所示:
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
FSDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
----RAMDirectory
FSDirectory
……
可以看出,每次处理过10个.fnm文件(文件全名_ram_N.fnm),是在RAMDirectory中,然后就切换到FSDirectory中,这时输出到本地磁盘的索引目录中的索引文件是_N.fnm,可以从上面的实例图中看到_0.fnm、_1.fnm等等。
真正执行向_N.fnm文件中写入内容是在FieldInfos类的第二个write()方法中,可以从该方法的实现来看到底都写入了哪些内容:
public void write(IndexOutput output) throws IOException {
output.writeVInt(size());
for (int i = 0; i < size(); i++) {
FieldInfo fi = fieldInfo(i);
byte bits = 0x0;
if (fi.isIndexed) bits |= IS_INDEXED;
if (fi.storeTermVector) bits |= STORE_TERMVECTOR;
if (fi.storePositionWithTermVector) bits |= STORE_POSITIONS_WITH_TERMVECTOR;
if (fi.storeOffsetWithTermVector) bits |= STORE_OFFSET_WITH_TERMVECTOR;
if (fi.omitNorms) bits |= OMIT_NORMS;
if (fi.storePayloads) bits |= STORE_PAYLOADS;
output.writeString(fi.name);
output.writeByte(bits);
}
}
从后两行代码可以看出,首先写入了一个Field的名称(name),然后写入了一个byte值。这个byte的值可以根据从该FieldInfos类定义的一些标志经过位运算得到,从而从FieldIno的实例中读取Field的信息,根据Field的一些信息(如:是否被索引、是否存储词条向量等等)来设置byte bits,这些标志的定义为:
static final byte IS_INDEXED = 0x1;
static final byte STORE_TERMVECTOR = 0x2;
static final byte STORE_POSITIONS_WITH_TERMVECTOR = 0x4;
static final byte STORE_OFFSET_WITH_TERMVECTOR = 0x8;
static final byte OMIT_NORMS = 0x10;
static final byte STORE_PAYLOADS = 0x20;
_N.fdt文件和_N.fdx文件
接着,在DocumentWriter类中的addDocumet()方法中,根据Directory实例、segment的名称、一个FieldInfos的实例构造了一个FieldsWriter类的实例:
FieldsWriter fieldsWriter = new FieldsWriter(directory, segment, fieldInfos);
可以从FieldsWriter类的构造方法可以看出,实际上,根据生成的segment的名称(_ram_N和_N)创建了两个输出流对象:
FieldsWriter(Directory d, String segment, FieldInfos fn) throws IOException {
fieldInfos = fn;
fieldsStream = d.createOutput(segment + ".fdt");
indexStream = d.createOutput(segment + ".fdx");
}
这时,_N.fdt和_N.fdx文件就要生成了。
继续看DocumentWriter类中的addDocument()方法:
fieldsWriter.addDocument(doc);
这时进入到FieldsWriter类中了,在addDocument()方法中提取Field的信息,写入到,_N.fdt和_N.fdx文件中。FieldsWriter类的addDocument()方法实现如下:
final void addDocument(Document doc) throws IOException {
indexStream.writeLong(fieldsStream.getFilePointer()); // 向indexStream中(即_N.fdx文件)中写入fieldsStream(_N.fdt文件)流中的当前位置,也就是写入这个Field信息的位置
int storedCount = 0;
Iterator fieldIterator = doc.getFields().iterator();
while (fieldIterator.hasNext()) { // 循环遍历该Document中所有Field,统计需要存储的Field的个数
Fieldable field = (Fieldable) fieldIterator.next();
if (field.isStored())
storedCount++;
}
fieldsStream.writeVInt(storedCount); // 存储Document中需要存储的的Field的个数,写入到_N.fdt文件
fieldIterator = doc.getFields().iterator();
while (fieldIterator.hasNext()) {
Fieldable field = (Fieldable) fieldIterator.next();
// if the field as an instanceof FieldsReader.FieldForMerge, we're in merge mode
// and field.binaryValue() already returns the compressed value for a field
// with isCompressed()==true, so we disable compression in that case
boolean disableCompression = (field instanceof FieldsReader.FieldForMerge);
if (field.isStored()) { // 如果Field需要存储,将该Field的编号写入到_N.fdt文件
fieldsStream.writeVInt(fieldInfos.fieldNumber(field.name()));
byte bits = 0;
if (field.isTokenized())
bits |= FieldsWriter.FIELD_IS_TOKENIZED;
if (field.isBinary())
bits |= FieldsWriter.FIELD_IS_BINARY;
if (field.isCompressed())
bits |= FieldsWriter.FIELD_IS_COMPRESSED;
fieldsStream.writeByte(bits); // 将Field的是否分词,或是否压缩,或是否以二进制流存储,这些信息都写入到_N.fdt文件
if (field.isCompressed()) {
// 如果当前Field可以被压缩
byte[] data = null;
if (disableCompression) {
// 已经被压缩过,科恩那个需要进行合并优化
data = field.binaryValue();
} else {
// 检查Field是否以二进制存储
if (field.isBinary()) {
data = compress(field.binaryValue());
}
else { // 设置编码方式,压缩存储处理
data = compress(field.stringValue().getBytes("UTF-8"));
}
}
final int len = data.length;
fieldsStream.writeVInt(len); // 写入Field名称(以二进制存储)的长度到_N.fdt文件
fieldsStream.writeBytes(data, len); // 通过字节流的方式,写入Field名称(以二进制存储)到_N.fdt文件
}
else {
// 如果当前这个Field不能进行压缩
if (field.isBinary()) {
byte[] data = field.binaryValue();
final int len = data.length;
fieldsStream.writeVInt(len);
fieldsStream.writeBytes(data, len);
}
else {
fieldsStream.writeString(field.stringValue()); // 如果Field不是以二进制存储,则以String的格式写入到_N.fdt文件
}
}
}
}
}
从该方法可以看出:
_N.fdx文件(即indexStream流)中写入的内容是:一个Field在_N.fdt文件中位置。
_N.fdt文件(即fieldsStream流)中写入的内容是:
(1) Document中需要存储的Field的数量;
(2) 每个Field在Document中的编号;
(3) 每个Field关于是否分词、是否压缩、是否以二进制存储这三个指标的一个组合值;
(4) 每个Field的长度;
(5) 每个Field的内容(binaryValue或stringValue);
_N.frq文件和_N.prx文件
仍然在DocumentWriter类的addDocument()方法中看:
writePostings(postings, segment);
因为在调用该方法之前,已经对Documeng进行了倒排,在倒排的过程中对Document中的Field进行了处理,如果Field指定了要进行分词,则在倒排的时候进行了分词处理,这时生成了词条。然后调用writePostings()方法,根据生成的segment的名称_ram_N,设置词条的频率、位置等信息,并写入到索引目录中。
在writePostings()方法中,首先创建了两个输出流:
freq = directory.createOutput(segment + ".frq");
prox = directory.createOutput(segment + ".prx");
这时,_N.frq文件和_N.prx文件就要在索引目录中生成了。
经过倒排,各个词条的重要信息都被存储到了Posting对象中,Posting类是为词条的信息服务的。因此,在writePostings()方法中可以遍历Posting[]数组中的各个Posting实例,读取并处理这些信息,然后输出到索引目录中。
设置_N.frq文件的起始写入内容:
int postingFreq = posting.freq;
if (postingFreq == 1) // 如果该词条第一次出现造Document中
freq.writeVInt(1); // 频率色绘制为1
else {
freq.writeVInt(0); // 如果不是第一次出现,对应的Document的编号0要写入到_N.frq文件
freq.writeVInt(postingFreq); // 设置一个词条在该Document中的频率值
}
再看prox输出流:
if (payloadLength == lastPayloadLength) { // 其中,int lastPayloadLength = -1;
// the length of the current payload equals the length
// of the previous one. So we do not have to store the length
// again and we only shift the position delta by one bit
prox.writeVInt(delta * 2); //其中,int delta = position - lastPosition,int position = positions[j];
} else {
// the length of the current payload is different from the
// previous one. We shift the position delta, set the lowest
// bit and store the current payload length as VInt.
prox.writeVInt(delta * 2 + 1);
prox.writeVInt(payloadLength);
lastPayloadLength = payloadLength;
}
if (payloadLength > 0) {
// write current payload
prox.writeBytes(payload.data, payload.offset, payload.length);
}
} else {
// field does not store payloads, just write position delta as VInt
prox.writeVInt(delta);
}
一个Posting包含了关于一个词条在一个Document中出现的所有位置(用一个int[]数组来描述)、频率(int)、该词条对应的所有的Payload信息(用Payload[]来描述,因为一个词条具有了频率信息,自然就对应了多个Payload)。
关于Payload可以参考文章 Lucene-2.2.0 源代码阅读学习(23) 。
_N.prx文件文件写入的内容都是与位置相关的数据。
从上面可以看出:
_N.frq文件(即freq流)中写入的内容是:
(1) 一个词条所在的Document的编号;
(2) 每个词条在Document中频率(即:出现的次数);
_N.prx文件(即prox流)中写入的内容是:
其实主要就是Payload的信息,如:一个词条对应的Payload的长度信息、起始偏移量信息;
_N.nrm文件
在DocumentWriter类的addDocument()方法中可以看到调用了writeNorms()方法:
writeNorms(segment);
也是根据生成的segment的名称_ram_N来创建一个输出流,看writeNorms()方法的定义:
private final void writeNorms(String segment) throws IOException {
for(int n = 0; n < fieldInfos.size(); n++){
FieldInfo fi = fieldInfos.fieldInfo(n);
if(fi.isIndexed && !fi.omitNorms){
float norm = fieldBoosts[n] * similarity.lengthNorm(fi.name, fieldLengths[n]);
IndexOutput norms = directory.createOutput(segment + ".f" + n);
try {
norms.writeByte(Similarity.encodeNorm(norm));
} finally {
norms.close();
}
}
}
}
将一些标准化因子的信息,都写入到了_N.nrm文件。其中每个segment对应着一个_N.nrm文件。
关于标准化因子可以参考文章 Lucene-2.2.0 源代码阅读学习(19) ,或者直接参考Apache官方网站http://lucene.apache.org/java/docs/fileformats.html#Normalization%20Factors。
关于不同格式的索引文件的内容示例
为了直观,写一个简单的例子:
package org.shirdrn.lucene;
import java.io.IOException;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.LockObtainFailedException;
public class LuceneIndexFormat {
public static void main(String[] args) {
String indexPath = "E:\\Lucene\\myindex";
String maven = "Maven is a software project management and comprehension tool.";
String lucene = "Apache Lucene is a search engine written entirely in Java.";
Document doc1 = new Document();
doc1.add(new Field("maven",maven,Field.Store.YES,Field.Index.TOKENIZED));
Document doc2 = new Document();
doc2.add(new Field("lucene",lucene,Field.Store.YES,Field.Index.TOKENIZED));
try {
IndexWriter indexWriter = new IndexWriter(indexPath,new StandardAnalyzer(),true);
indexWriter.setUseCompoundFile(false);
indexWriter.addDocument(doc1);
indexWriter.addDocument(doc2);
indexWriter.close();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (LockObtainFailedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行主函数后,在指定的索引目录下生成了索引文件,而且是同一个索引段,如图所示:
使用UltraEdit-32打开_0.fnm文件,可以看到内容如下所示:
就是我们在程序中设置的,即:
doc.add(new Field("maven",maven,Field.Store.YES,Field.Index.TOKENIZED));
doc.add(new Field("lucene",lucene,Field.Store.YES,Field.Index.TOKENIZED));
就是这两个Field的name。
使用UltraEdit-32打开_0.fdt文件,可以看到内容如下所示:
其实,就是Field的内容。(上面的文本内容实际上存储在一行)
使用UltraEdit-32打开_0.fdx文件,可以看到内容如下所示:
其实,就是在_0.fdt文件中,两个Field的存放位置。
第一个Field是从0位置开始的,第二个是从42(这里是16进制,十进制为66)位置开始的。
使用UltraEdit-32打开_0.nrm文件,可以看到内容如下所示:
这里是标准化因子信息。
(关于标准化因子可以参考文章 Lucene-2.2.0 源代码阅读学习(19) ,或者直接参考Apache官方网站http://lucene.apache.org/java/docs/fileformats.html#Normalization%20Factors。)
发表评论
-
创建索引的时候出现的错误
2010-01-04 10:13 1702<OFMsg>251658517"1&q ... -
SQLServer2005获取大数据集时内存不足的解决办法
2009-02-12 10:59 1991今天在修改search的建立索引的程序的时候,发现了这个错误 ... -
使用Lucene的Highlighter实现文件摘要的自动提取
2009-02-06 16:52 6648使用Lucene自带的Highlighter就可以实现对原始文 ... -
Lucene倒排索引原理
2009-02-06 16:08 1154Lucene是一个高性能的java全文检索工具包,它使用的是倒 ... -
Lucene 2.2.0发布自带的HTMLParser的使用
2009-02-06 16:00 2538Lucene 2.2.0发行包中自带 ... -
Lucene关键字高亮显示
2009-02-06 15:53 2375在Lucene的org.apache.lucene.s ... -
Lucene-2.2.0 源代码阅读学习(42)
2009-02-06 15:46 1332关于Hits类。这个Hits类 ... -
Lucene-2.2.0 源代码阅读学习(41)
2009-02-06 15:40 1110当执行Hits htis = search(query);这一 ... -
Lucene-2.2.0 源代码阅读学习(40)
2009-02-06 15:34 1195关于Lucene检索结果的排序问题。 已经知道,Lucene的 ... -
Lucene-2.2.0 源代码阅读学习(39)
2009-02-06 15:31 1118关于Lucene得分的计算。 在IndexSearcher类中 ... -
Lucene-2.2.0 源代码阅读学习(38)
2009-02-06 15:13 1130关于QueryParser。 QueryParser是用来解析 ... -
Lucene-2.2.0 源代码阅读学习(37)
2009-02-06 15:06 1065关于MultiTermQuery查询。 这里研究继承自Mult ... -
Lucene-2.2.0 源代码阅读学习(36)
2009-02-06 15:05 1018关于MultiTermQuery查询。 这里研究FuzzyQu ... -
Lucene-2.2.0 源代码阅读学习(35)
2009-02-06 15:03 941于MultiPhraseQuery(多短语查询)。 Multi ... -
Lucene-2.2.0 源代码阅读学习(34)
2009-02-06 15:02 972关于PhraseQuery。 PhraseQuery查询是将多 ... -
Lucene-2.2.0 源代码阅读学习(33)
2009-02-06 15:01 996关于范围查询RangeQuery。 ... -
Lucene-2.2.0 源代码阅读学习(32)
2009-02-06 15:00 889关于SpanQuery(跨度搜索),它是Query的子类,但是 ... -
Lucene-2.2.0 源代码阅读学习(31)
2009-02-06 14:58 947关于前缀查询PrefixQuery(前缀查询)。 准备工作就是 ... -
Lucene-2.2.0 源代码阅读学习(30)
2009-02-06 14:57 755关于Query的学习。 主要使用TermQuery和Boole ... -
Lucene-2.2.0 源代码阅读学习(29)
2009-02-06 14:54 1159关于IndexSearcher检索器。 ...
相关推荐
lucene-analyzers-2.2.0.jarlucene-analyzers-2.2.0.jarlucene-analyzers-2.2.0.jarlucene-analyzers-2.2.0.jarlucene-analyzers-2.2.0.jarlucene-analyzers-2.2.0.jarlucene-analyzers-2.2.0.jarlucene-analyzers-...
标题中的"lucene-2.2.0zip"指的是Lucene的2.2.0版本,这是一个较早的版本,对于学习和理解Lucene的基础概念非常有帮助。 Lucene 2.2.0的主要特性包括: 1. **全文检索**:Lucene支持对文档内容进行全文检索,允许...
lucene-highlighter-2.2.0.jarlucene-highlighter-2.2.0.jarlucene-highlighter-2.2.0.jarlucene-highlighter-2.2.0.jarlucene-highlighter-2.2.0.jarlucene-highlighter-2.2.0.jarlucene-highlighter-2.2.0.jar
《Lucene-2.3.1 源代码阅读学习》 Lucene是Apache软件基金会的一个开放源码项目,它是一个高性能、全文本搜索库,为开发者提供了在Java应用程序中实现全文检索功能的基础架构。本篇文章将深入探讨Lucene 2.3.1版本...
《深入解析Lucene高亮显示源码:剖析`lucene-highlighter-2.2.0-src.zip`》 Lucene,作为一个开源全文检索库,以其高效、灵活的特点在信息检索领域广泛应用。在处理搜索结果时,为了提升用户体验,通常会采用高亮...
《深入剖析Lucene 2.2.0源代码》 Lucene是一款强大的开源全文搜索引擎库,由Apache软件基金会开发并维护。它为Java开发者提供了一种高性能、可扩展的文本检索核心工具。本文将深入探讨Lucene 2.2.0版本的源代码,...
在前面Lucene-2.2.0 源代码阅读学习(1)中,根据Lucene提供的一个Demo,详细分析研究一下索引器org.apache.lucene.index.IndexWriter类,看看它是如果定义的,掌握它建立索引的机制。 通过IndexWriter类的实现源代码...
赠送源代码:lucene-analyzers-smartcn-7.7.0-sources.jar; 赠送Maven依赖信息文件:lucene-analyzers-smartcn-7.7.0.pom; 包含翻译后的API文档:lucene-analyzers-smartcn-7.7.0-javadoc-API文档-中文(简体)版....
赠送源代码:lucene-core-7.7.0-sources.jar; 赠送Maven依赖信息文件:lucene-core-7.7.0.pom; 包含翻译后的API文档:lucene-core-7.7.0-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.apache.lucene:lucene...
- 通过阅读源代码,可以理解Lucene的内部工作原理,如如何构建索引、执行查询等。 - 分析器部分的源码有助于了解文本预处理过程,包括分词、去除停用词等。 - 探究查询解析器的实现,掌握如何将自然语言转化为...
赠送源代码:lucene-analyzers-common-6.6.0-sources.jar; 赠送Maven依赖信息文件:lucene-analyzers-common-6.6.0.pom; 包含翻译后的API文档:lucene-analyzers-common-6.6.0-javadoc-API文档-中文(简体)版.zip;...
这是一个java开发用的.jar文件,用它和Lucene-core-2.0.0.jar可以实现搜索引擎
赠送源代码:lucene-core-7.2.1-sources.jar; 赠送Maven依赖信息文件:lucene-core-7.2.1.pom; 包含翻译后的API文档:lucene-core-7.2.1-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.apache.lucene:lucene...
赠送源代码:lucene-suggest-6.6.0-sources.jar; 赠送Maven依赖信息文件:lucene-suggest-6.6.0.pom; 包含翻译后的API文档:lucene-suggest-6.6.0-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.apache....
赠送源代码:lucene-backward-codecs-7.3.1-sources.jar; 赠送Maven依赖信息文件:lucene-backward-codecs-7.3.1.pom; 包含翻译后的API文档:lucene-backward-codecs-7.3.1-javadoc-API文档-中文(简体)-英语-对照...
赠送源代码:lucene-core-6.6.0-sources.jar; 赠送Maven依赖信息文件:lucene-core-6.6.0.pom; 包含翻译后的API文档:lucene-core-6.6.0-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.apache.lucene:lucene...
赠送源代码:lucene-spatial-extras-7.3.1-sources.jar; 赠送Maven依赖信息文件:lucene-spatial-extras-7.3.1.pom; 包含翻译后的API文档:lucene-spatial-extras-7.3.1-javadoc-API文档-中文(简体)-英语-对照版....
赠送源代码:lucene-memory-6.6.0-sources.jar; 赠送Maven依赖信息文件:lucene-memory-6.6.0.pom; 包含翻译后的API文档:lucene-memory-6.6.0-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.apache.lucene:...
赠送源代码:lucene-suggest-7.7.0-sources.jar; 赠送Maven依赖信息文件:lucene-suggest-7.7.0.pom; 包含翻译后的API文档:lucene-suggest-7.7.0-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.apache....
赠送源代码:lucene-analyzers-smartcn-7.7.0-sources.jar; 赠送Maven依赖信息文件:lucene-analyzers-smartcn-7.7.0.pom; 包含翻译后的API文档:lucene-analyzers-smartcn-7.7.0-javadoc-API文档-中文(简体)-英语...