zoukankan      html  css  js  c++  java
  • Solr4.8.0源码分析(7)之Solr SPI

    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"时,程序输出是:

    now use file system search. keyword:test

    当search.Search文件内容是"search.DatabaseSearch"时,程序输出是:

    now use 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的实例类,并放入services MAP里面

    3.Codec默认为Lucene46,从services MAP获取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 }
    转载请注明地址http://www.cnblogs.com/rcfeng/
  • 相关阅读:

    【工作】---前后端联调
    【react】---Immutable的基本使用
    【react】传值
    【原生】 HTML DOM 事件,各种事件类型、事件种类
    两台笔记本电脑之间实现屏幕扩展
    【看图学习后台管理系统】
    【bug】在react开发中,使用link 跳转中,无法点击跳转的问题
    【前端工程师】 web 安全问题
    【前端工程师】 性能和效率 优化的问题
  • 原文地址:https://www.cnblogs.com/rcfeng/p/3932045.html
Copyright © 2011-2022 走看看