Solr4.8.0源码分析(7)之Solr SPI
查看Solr源码时候会发现,每一个package都会由对应的resources. 如下图所示:
一时对这玩意好奇了,看了文档以后才发现,这个services就是java SPI机制。首先介绍下java SPI机制,然后再结合Solr谈一下SPI。
1. JAVA SPI
当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。
基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。
jdk提供服务实现查找的一个工具类:java.util.ServiceLoader
假设有一个内容搜索系统,分为展示和搜索两个模块。展示和搜索基于接口编程。搜索的实现可能是基于文件系统的搜索,也可能是基于数据库的搜索。实例代码如下:
Search.java: 搜索接口
1 package search;
2
3 import java.util.List;
4
5 import definition.Doc;
6
7 public interface Search {
8 List<Doc> search(String keyword);
9 }
FileSearch.java:文件系统的搜索实现
1 package search;
2
3 import java.util.List;
4
5 import definition.Doc;
6
7 public class FileSearch implements Search {
8
9 @Override
10 public List<Doc> search(String keyword) {
11 System.out.println("now use file system search. keyword:" + keyword);
12 return null;
13 }
14
15 }
DatabaseSearch.java
1 package search;
2
3 import java.util.List;
4
5 import definition.Doc;
6
7 public class DatabaseSearch implements Search {
8
9 @Override
10 public List<Doc> search(String keyword) {
11 System.out.println("now use database search. keyword:" + keyword);
12 return null;
13 }
14
15 }
SearchTest.java
1 package search;
2
3 import java.util.Iterator;
4 import java.util.ServiceLoader;
5
6 public class SearchTest {
7
8 public static void main(String[] args) {
9 ServiceLoader<Search> s = ServiceLoader.load(Search.class);
10 Iterator<Search> searchs = s.iterator();
11 if (searchs.hasNext()) {
12 Search curSearch = searchs.next();
13 curSearch.search("test");
14 }
15 }
16 }
最后创建在META-INF/searvices/search.Search文件。
当search.Search文件内容是"search.FileSearch"时,程序输出是:
nowuse file system search. keyword:test
当search.Search文件内容是"search.DatabaseSearch"时,程序输出是:
nowuse database search. keyword:test
可以看出SearchTest里没有任何和具体实现有关的代码,而是基于spi的机制去查找服务的实现。
2. Solr SPI
以Codec类为例,查看resources/META-INF/services/org.apache.lucene.codecs.Codec:可以看出Codec服务接口具有以下具体的实现类。这就很好的解释了Solrconfig.xml里面的LuceneVersion的配置,也为Lucene的向前兼容提供了保障。
1 # Licensed to the Apache Software Foundation (ASF) under one or more
2 # contributor license agreements. See the NOTICE file distributed with
3 # this work for additional information regarding copyright ownership.
4 # The ASF licenses this file to You under the Apache License, Version 2.0
5 # (the "License"); you may not use this file except in compliance with
6 # the License. You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 org.apache.lucene.codecs.lucene40.Lucene40Codec
17 org.apache.lucene.codecs.lucene3x.Lucene3xCodec
18 org.apache.lucene.codecs.lucene41.Lucene41Codec
19 org.apache.lucene.codecs.lucene42.Lucene42Codec
20 org.apache.lucene.codecs.lucene45.Lucene45Codec
21 org.apache.lucene.codecs.lucene46.Lucene46Codec
接下来可以看下Codec服务接口的实现代码
1 package org.apache.lucene.codecs;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership.
7 * The ASF licenses this file to You under the Apache License, Version 2.0
8 * (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 import java.util.Set;
21 import java.util.ServiceLoader; // javadocs
22
23 import org.apache.lucene.index.IndexWriterConfig; // javadocs
24 import org.apache.lucene.util.NamedSPILoader;
25
26 /**
27 * Encodes/decodes an inverted index segment.
28 * <p>
29 * Note, when extending this class, the name ({@link #getName}) is
30 * written into the index. In order for the segment to be read, the
31 * name must resolve to your implementation via {@link #forName(String)}.
32 * This method uses Java's
33 * {@link ServiceLoader Service Provider Interface} (SPI) to resolve codec names.
34 * <p>
35 * If you implement your own codec, make sure that it has a no-arg constructor
36 * so SPI can load it.
37 * @see ServiceLoader
38 */
39 public abstract class Codec implements NamedSPILoader.NamedSPI {
40
41 private static final NamedSPILoader<Codec> loader =
42 new NamedSPILoader<>(Codec.class);
43
44 private final String name;
45
46 /**
47 * Creates a new codec.
48 * <p>
49 * The provided name will be written into the index segment: in order to
50 * for the segment to be read this class should be registered with Java's
51 * SPI mechanism (registered in META-INF/ of your jar file, etc).
52 * @param name must be all ascii alphanumeric, and less than 128 characters in length.
53 */
54 protected Codec(String name) {
55 NamedSPILoader.checkServiceName(name);
56 this.name = name;
57 }
58
59 /** Returns this codec's name */
60 @Override
61 public final String getName() {
62 return name;
63 }
64 /**
65 * 以下几个Format跟Lucene的索引文件格式有关
66 * */
67 /** Encodes/decodes postings */
68 public abstract PostingsFormat postingsFormat();
69
70 /** Encodes/decodes docvalues */
71 public abstract DocValuesFormat docValuesFormat();
72
73 /** Encodes/decodes stored fields */
74 public abstract StoredFieldsFormat storedFieldsFormat();
75
76 /** Encodes/decodes term vectors */
77 public abstract TermVectorsFormat termVectorsFormat();
78
79 /** Encodes/decodes field infos file */
80 public abstract FieldInfosFormat fieldInfosFormat();
81
82 /** Encodes/decodes segment info file */
83 public abstract SegmentInfoFormat segmentInfoFormat();
84
85 /** Encodes/decodes document normalization values */
86 public abstract NormsFormat normsFormat();
87
88 /** Encodes/decodes live docs */
89 public abstract LiveDocsFormat liveDocsFormat();
90
91 /**
92 * 根据名字在已有的Codec实例中寻找符合
93 * */
94 /** looks up a codec by name */
95 public static Codec forName(String name) {
96 if (loader == null) {
97 throw new IllegalStateException("You called Codec.forName() before all Codecs could be initialized. "+
98 "This likely happens if you call it from a Codec's ctor.");
99 }
100 return loader.lookup(name);
101 }
102
103 /**
104 * 返回有效的Codecs实例
105 * */
106 /** returns a list of all available codec names */
107 public static Set<String> availableCodecs() {
108 if (loader == null) {
109 throw new IllegalStateException("You called Codec.availableCodecs() before all Codecs could be initialized. "+
110 "This likely happens if you call it from a Codec's ctor.");
111 }
112 return loader.availableServices();
113 }
114
115 /**
116 * 更新Codec实例列表,Codec实例列表只能添加,不能删除与更改。
117 * */
118 /**
119 * Reloads the codec list from the given {@link ClassLoader}.
120 * Changes to the codecs are visible after the method ends, all
121 * iterators ({@link #availableCodecs()},...) stay consistent.
122 *
123 * <p><b>NOTE:</b> Only new codecs are added, existing ones are
124 * never removed or replaced.
125 *
126 * <p><em>This method is expensive and should only be called for discovery
127 * of new codecs on the given classpath/classloader!</em>
128 */
129 public static void reloadCodecs(ClassLoader classloader) {
130 loader.reload(classloader);
131 }
132
133 /**
134 * 默认为Lucene46,也就是说默认调用的是org.apache.lucene.codecs.lucene46.Lucene46Codec
135 * */
136 private static Codec defaultCodec = Codec.forName("Lucene46");
137
138 /**
139 * 返回默认的Codec实例
140 * */
141 /** expert: returns the default codec used for newly created
142 * {@link IndexWriterConfig}s.
143 */
144 // TODO: should we use this, or maybe a system property is better?
145 public static Codec getDefault() {
146 return defaultCodec;
147 }
148
149 /**
150 * 设置默认的Codec实例
151 * */
152 /** expert: sets the default codec used for newly created
153 * {@link IndexWriterConfig}s.
154 */
155 public static void setDefault(Codec codec) {
156 defaultCodec = codec;
157 }
158
159 /**
160 * returns the codec's name. Subclasses can override to provide
161 * more detail (such as parameters).
162 */
163 @Override
164 public String toString() {
165 return name;
166 }
167 }
代码比较简单明了,接下来再看下NamedSPILoader.NamedSPI,它封装了JAVA SPI的实现:
1 package org.apache.lucene.util;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership.
7 * The ASF licenses this file to You under the Apache License, Version 2.0
8 * (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 import java.util.Collections;
21 import java.util.Iterator;
22 import java.util.Map;
23 import java.util.LinkedHashMap;
24 import java.util.Set;
25 import java.util.ServiceConfigurationError;
26
27 /**
28 * Helper class for loading named SPIs from classpath (e.g. Codec, PostingsFormat).
29 * @lucene.internal
30 */
31 public final class NamedSPILoader<S extends NamedSPILoader.NamedSPI> implements Iterable<S> {
32
33 /**
34 * SPI service Map,存放服务对应的实例类。
35 * */
36 private volatile Map<String,S> services = Collections.emptyMap();
37 private final Class<S> clazz;
38
39 public NamedSPILoader(Class<S> clazz) {
40 this(clazz, Thread.currentThread().getContextClassLoader());
41 }
42
43 public NamedSPILoader(Class<S> clazz, ClassLoader classloader) {
44 this.clazz = clazz;
45 // if clazz' classloader is not a parent of the given one, we scan clazz's classloader, too:
46 final ClassLoader clazzClassloader = clazz.getClassLoader();
47 if (clazzClassloader != null && !SPIClassIterator.isParentClassLoader(clazzClassloader, classloader)) {
48 reload(clazzClassloader);
49 }
50 reload(classloader);
51 }
52
53 /**
54 * 更新SPI MAP services。遍历META-INF/services文件,如果services MAP没有该实例,则新建实例,并放入services MAP
55 * */
56 /**
57 * Reloads the internal SPI list from the given {@link ClassLoader}.
58 * Changes to the service list are visible after the method ends, all
59 * iterators ({@link #iterator()},...) stay consistent.
60 *
61 * <p><b>NOTE:</b> Only new service providers are added, existing ones are
62 * never removed or replaced.
63 *
64 * <p><em>This method is expensive and should only be called for discovery
65 * of new service providers on the given classpath/classloader!</em>
66 */
67 public synchronized void reload(ClassLoader classloader) {
68 final LinkedHashMap<String,S> services = new LinkedHashMap<>(this.services);
69 final SPIClassIterator<S> loader = SPIClassIterator.get(clazz, classloader);
70 while (loader.hasNext()) {
71 final Class<? extends S> c = loader.next();
72 try {
73 final S service = c.newInstance();
74 final String name = service.getName();
75 // only add the first one for each name, later services will be ignored
76 // this allows to place services before others in classpath to make
77 // them used instead of others
78 if (!services.containsKey(name)) {
79 checkServiceName(name);
80 services.put(name, service);
81 }
82 } catch (Exception e) {
83 throw new ServiceConfigurationError("Cannot instantiate SPI class: " + c.getName(), e);
84 }
85 }
86 this.services = Collections.unmodifiableMap(services);
87 }
88
89 /**
90 * Validates that a service name meets the requirements of {@link NamedSPI}
91 */
92 public static void checkServiceName(String name) {
93 // based on harmony charset.java
94 if (name.length() >= 128) {
95 throw new IllegalArgumentException("Illegal service name: '" + name + "' is too long (must be < 128 chars).");
96 }
97 for (int i = 0, len = name.length(); i < len; i++) {
98 char c = name.charAt(i);
99 if (!isLetterOrDigit(c)) {
100 throw new IllegalArgumentException("Illegal service name: '" + name + "' must be simple ascii alphanumeric.");
101 }
102 }
103 }
104
105 /**
106 * Checks whether a character is a letter or digit (ascii) which are defined in the spec.
107 */
108 private static boolean isLetterOrDigit(char c) {
109 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9');
110 }
111
112 /**
113 * 在Services MAP里面查找是否已有name的实例
114 * */
115 public S lookup(String name) {
116 final S service = services.get(name);
117 if (service != null) return service;
118 throw new IllegalArgumentException("A SPI class of type "+clazz.getName()+" with name '"+name+"' does not exist. "+
119 "You need to add the corresponding JAR file supporting this SPI to your classpath."+
120 "The current classpath supports the following names: "+availableServices());
121 }
122
123 public Set<String> availableServices() {
124 return services.keySet();
125 }
126
127 @Override
128 public Iterator<S> iterator() {
129 return services.values().iterator();
130 }
131
132 /**
133 * Interface to support {@link NamedSPILoader#lookup(String)} by name.
134 * <p>
135 * Names must be all ascii alphanumeric, and less than 128 characters in length.
136 */
137 public static interface NamedSPI {
138 String getName();
139 }
140
141 }
接下来看看Solr是怎么获取services的实例信息的
1 package org.apache.lucene.util;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership.
7 * The ASF licenses this file to You under the Apache License, Version 2.0
8 * (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.BufferedReader;
23 import java.io.InputStreamReader;
24 import java.net.URL;
25 import java.nio.charset.StandardCharsets;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.Enumeration;
29 import java.util.Iterator;
30 import java.util.Locale;
31 import java.util.NoSuchElementException;
32 import java.util.ServiceConfigurationError;
33
34 /**
35 * Helper class for loading SPI classes from classpath (META-INF files).
36 * This is a light impl of {@link java.util.ServiceLoader} but is guaranteed to
37 * be bug-free regarding classpath order and does not instantiate or initialize
38 * the classes found.
39 *
40 * @lucene.internal
41 */
42 public final class SPIClassIterator<S> implements Iterator<Class<? extends S>> {
43 //service路径
44 private static final String META_INF_SERVICES = "META-INF/services/";
45
46 private final Class<S> clazz;
47 private final ClassLoader loader;
48 private final Enumeration<URL> profilesEnum;
49 private Iterator<String> linesIterator;
50
51 public static <S> SPIClassIterator<S> get(Class<S> clazz) {
52 return new SPIClassIterator<>(clazz, Thread.currentThread().getContextClassLoader());
53 }
54
55 public static <S> SPIClassIterator<S> get(Class<S> clazz, ClassLoader loader) {
56 return new SPIClassIterator<>(clazz, loader);
57 }
58
59 /** Utility method to check if some class loader is a (grand-)parent of or the same as another one.
60 * This means the child will be able to load all classes from the parent, too. */
61 public static boolean isParentClassLoader(final ClassLoader parent, ClassLoader child) {
62 while (child != null) {
63 if (child == parent) {
64 return true;
65 }
66 child = child.getParent();
67 }
68 return false;
69 }
70
71 /**
72 * 解析META-INF/services/clazz.getname文件
73 * */
74 private SPIClassIterator(Class<S> clazz, ClassLoader loader) {
75 this.clazz = clazz;
76 try {
77 final String fullName = META_INF_SERVICES + clazz.getName();
78 this.profilesEnum = (loader == null) ? ClassLoader.getSystemResources(fullName) : loader.getResources(fullName);
79 } catch (IOException ioe) {
80 throw new ServiceConfigurationError("Error loading SPI profiles for type " + clazz.getName() + " from classpath", ioe);
81 }
82 this.loader = (loader == null) ? ClassLoader.getSystemClassLoader() : loader;
83 this.linesIterator = Collections.<String>emptySet().iterator();
84 }
85
86 /**
87 * 获取META-INF/services/clazz.getname的clazz服务实例
88 * */
89 private boolean loadNextProfile() {
90 ArrayList<String> lines = null;
91 while (profilesEnum.hasMoreElements()) {
92 if (lines != null) {
93 lines.clear();
94 } else {
95 lines = new ArrayList<>();
96 }
97 final URL url = profilesEnum.nextElement();
98 try {
99 final InputStream in = url.openStream();
100 IOException priorE = null;
101 try {
102 final BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
103 String line;
104 while ((line = reader.readLine()) != null) {
105 final int pos = line.indexOf('#');
106 if (pos >= 0) {
107 line = line.substring(0, pos);
108 }
109 line = line.trim();
110 if (line.length() > 0) {
111 lines.add(line);
112 }
113 }
114 } catch (IOException ioe) {
115 priorE = ioe;
116 } finally {
117 IOUtils.closeWhileHandlingException(priorE, in);
118 }
119 } catch (IOException ioe) {
120 throw new ServiceConfigurationError("Error loading SPI class list from URL: " + url, ioe);
121 }
122 if (!lines.isEmpty()) {
123 this.linesIterator = lines.iterator();
124 return true;
125 }
126 }
127 return false;
128 }
129
130 @Override
131 public boolean hasNext() {
132 return linesIterator.hasNext() || loadNextProfile();
133 }
134
135 @Override
136 public Class<? extends S> next() {
137 // hasNext() implicitely loads the next profile, so it is essential to call this here!
138 if (!hasNext()) {
139 throw new NoSuchElementException();
140 }
141 assert linesIterator.hasNext();
142 final String c = linesIterator.next();
143 try {
144 // don't initialize the class (pass false as 2nd parameter):
145 return Class.forName(c, false, loader).asSubclass(clazz);
146 } catch (ClassNotFoundException cnfe) {
147 throw new ServiceConfigurationError(String.format(Locale.ROOT, "A SPI class of type %s with classname %s does not exist, "+
148 "please fix the file '%s%1$s' in your classpath.", clazz.getName(), c, META_INF_SERVICES));
149 }
150 }
151
152 @Override
153 public void remove() {
154 throw new UnsupportedOperationException();
155 }
156
157 }
由此可见SOLR SPI的流程是如下的:以Codec为例
1、 SPIClassIterator获取所有META-INF/services/org.apache.lucene.codecs.Codec的实例类信息;
2、 NamedSPILoader实例化所有META-INF/services/org.apache.lucene.codecs.Codec的实例类,并放入servicesMAP里面;
3、 Codec默认为Lucene46,从servicesMAP获取Lucene46的实例类org.apache.lucene.codecs.lucene46.Lucene46Codec;
1 package org.apache.lucene.codecs.lucene46;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership.
7 * The ASF licenses this file to You under the Apache License, Version 2.0
8 * (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 import org.apache.lucene.codecs.Codec;
21 import org.apache.lucene.codecs.DocValuesFormat;
22 import org.apache.lucene.codecs.FieldInfosFormat;
23 import org.apache.lucene.codecs.FilterCodec;
24 import org.apache.lucene.codecs.LiveDocsFormat;
25 import org.apache.lucene.codecs.NormsFormat;
26 import org.apache.lucene.codecs.PostingsFormat;
27 import org.apache.lucene.codecs.SegmentInfoFormat;
28 import org.apache.lucene.codecs.StoredFieldsFormat;
29 import org.apache.lucene.codecs.TermVectorsFormat;
30 import org.apache.lucene.codecs.lucene40.Lucene40LiveDocsFormat;
31 import org.apache.lucene.codecs.lucene41.Lucene41StoredFieldsFormat;
32 import org.apache.lucene.codecs.lucene42.Lucene42NormsFormat;
33 import org.apache.lucene.codecs.lucene42.Lucene42TermVectorsFormat;
34 import org.apache.lucene.codecs.perfield.PerFieldDocValuesFormat;
35 import org.apache.lucene.codecs.perfield.PerFieldPostingsFormat;
36
37 /**
38 * Implements the Lucene 4.6 index format, with configurable per-field postings
39 * and docvalues formats.
40 * <p>
41 * If you want to reuse functionality of this codec in another codec, extend
42 * {@link FilterCodec}.
43 *
44 * @see org.apache.lucene.codecs.lucene46 package documentation for file format details.
45 * @lucene.experimental
46 */
47 // NOTE: if we make largish changes in a minor release, easier to just make Lucene46Codec or whatever
48 // if they are backwards compatible or smallish we can probably do the backwards in the postingsreader
49 // (it writes a minor version, etc).
50 public class Lucene46Codec extends Codec {
51 private final StoredFieldsFormat fieldsFormat = new Lucene41StoredFieldsFormat();
52 private final TermVectorsFormat vectorsFormat = new Lucene42TermVectorsFormat();
53 private final FieldInfosFormat fieldInfosFormat = new Lucene46FieldInfosFormat();
54 private final SegmentInfoFormat segmentInfosFormat = new Lucene46SegmentInfoFormat();
55 private final LiveDocsFormat liveDocsFormat = new Lucene40LiveDocsFormat();
56
57 private final PostingsFormat postingsFormat = new PerFieldPostingsFormat() {
58 @Override
59 public PostingsFormat getPostingsFormatForField(String field) {
60 return Lucene46Codec.this.getPostingsFormatForField(field);
61 }
62 };
63
64 private final DocValuesFormat docValuesFormat = new PerFieldDocValuesFormat() {
65 @Override
66 public DocValuesFormat getDocValuesFormatForField(String field) {
67 return Lucene46Codec.this.getDocValuesFormatForField(field);
68 }
69 };
70
71 /** Sole constructor. */
72 public Lucene46Codec() {
73 super("Lucene46");
74 }
75
76 @Override
77 public final StoredFieldsFormat storedFieldsFormat() {
78 return fieldsFormat;
79 }
80
81 @Override
82 public final TermVectorsFormat termVectorsFormat() {
83 return vectorsFormat;
84 }
85
86 @Override
87 public final PostingsFormat postingsFormat() {
88 return postingsFormat;
89 }
90
91 @Override
92 public final FieldInfosFormat fieldInfosFormat() {
93 return fieldInfosFormat;
94 }
95
96 @Override
97 public final SegmentInfoFormat segmentInfoFormat() {
98 return segmentInfosFormat;
99 }
100
101 @Override
102 public final LiveDocsFormat liveDocsFormat() {
103 return liveDocsFormat;
104 }
105
106 /** Returns the postings format that should be used for writing
107 * new segments of <code>field</code>.
108 *
109 * The default implementation always returns "Lucene41"
110 */
111 public PostingsFormat getPostingsFormatForField(String field) {
112 return defaultFormat;
113 }
114
115 /** Returns the docvalues format that should be used for writing
116 * new segments of <code>field</code>.
117 *
118 * The default implementation always returns "Lucene45"
119 */
120 public DocValuesFormat getDocValuesFormatForField(String field) {
121 return defaultDVFormat;
122 }
123
124 @Override
125 public final DocValuesFormat docValuesFormat() {
126 return docValuesFormat;
127 }
128
129 private final PostingsFormat defaultFormat = PostingsFormat.forName("Lucene41");
130 private final DocValuesFormat defaultDVFormat = DocValuesFormat.forName("Lucene45");
131
132 private final NormsFormat normsFormat = new Lucene42NormsFormat();
133
134 @Override
135 public final NormsFormat normsFormat() {
136 return normsFormat;
137 }
138 }
版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: