精华内容
下载资源
问答
  • 2017-04-06 20:14:47

    5.2 Lucene索引器:
    5.2.1 Lucene索引介绍
    5.2.2 Lucene索引结构
    5.2.3 多文件索引结构
    5.2.4 复合索引结构

    5.2.1 Lucene索引介绍:
    文档索引 是 Lucene系统的核心功能。
    有专门的API用来实现索引的建立和管理功能。可处理多种格式的文档,如磁盘文件、电子邮件地址、网页及数据库记录等。
    Lucene的索引格式采用 独立索引模式 和 复合索引模式:
    1、独立索引模式:
    指每个Document独立索引成一个文件,这种方式检索速度比较快,但不是和大量文件的处理。
    2、复合索引模式:
    把等待索引的全部Document索引成一个文件,这个文件包含的文档内容各不相同,甚至包括域项目不同的异构型文档;

    Lucene的索引,通常以单个或者一系列索引文件形式放在系统目录中,可以存在内存(RAMDirectory)或者硬盘(FSDirectory)中。
    内存索引检索速度快,但关机后会丢失;硬盘索引可以长期保存,但是检索时需要进行IO操作,速度相对比较慢;实际多为两者结合。

    Lucene其他特点:
    1、索引结构以文件形式存储,不必依赖于数据库或者某种特定平台;
    2、支持分块索引,对新加入的文件建立新的索引,缩短索引生效的时间,然后通过索引合并建立整体索引;

    Lucene系统根据选用的索引生成形式不同可分为:复合索引格式和多文件索引格式。
    系统默认为复合索引格式,减少索引文件的数量,便于管理和使用。
    索引建立的过程会处理海量的数据,生成的索引段和索引文件会非常庞大。具体实现应根据任务特点来选择特定形式。
    复合索引通常在静态索引中比较合适,而在动态索引中采用多文件索引更为方便。

    5.2.2 Lucene索引结构:
    索引结构可以分为索引、索引段、索引文档、索引域和索引项几个不同层次。
    Lucene每个索引结构由一个或者多个段组成,每个段包含一个或多个文档,每个文档管理了一个或多个域,
    每个域由一个或多个索引项组成,每个索引项是一个索引数据。
    1、索引(Index):
    Lucene的索引结构最终体现到特定格式的磁盘文件来存储。索引在内存和磁盘中,都使用相同的逻辑结构。
    在磁盘上Lucene索引以格式化的文本形式存储,每个索引结构由一个或多个段来组成。
    磁盘文件包括当前活跃索引段 和 新建的索引文件, 通过工具可以把分段合并为统一的索引段。
    2、索引段(Segment):
    在每次创建的过程,文档都是添加到了特定的段里,然后索引段会根据参数合并。
    一个索引中只有一个没有后缀的Segment_* 文件,它记录当前索引中所有的segment情况。它的后缀根据包含段的不同而变化。
    索引段相当于子索引,新建的索引通常以一个新段形式出现,在合并操作后,每个索引体系只包含一个段。

    3、索引文档(Document):
    Document是索引器可以直接添加的对象,每个索引可以包含多个不同的文档,每个文档又管理了数目不等的域集合。
    这里的文档是一个逻辑概念,不同于我们通常意义所说的电子文本文件、Word文件等。
    它是Lucene索引对的真正可以检索索引项的一级管理框架。

    4、索引域(Field):
    域Field 是Document对象的基本组成单位。
    每个域内存储了时间的索引文本数据,这些文本数据在内部调用了分析器Analyzer的索引项结果。
    域内数据的检索查询最终是以索引项为单位的,比索引项更小的单位无法检索到。
    英文的索引项以单词为检索单位,中文以中文分词结果作为检索单位。
    Field有5种生成函数:
    - Field(String name, byte[] value, Field.Store store);
    - Field(String name, Reader reader);
    - Field(String name, Reader reader, Field.TermVector termVector);
    - Field(String name, String value, Field.Store store, Field.Index index);
    - Field(String name, String value, Field.Store store, Field.Index index, Field.TermVector termVector);

    – 其中第一个生成函数用于二进制数据索引,第2、3个生成函数用于文件内容的索引,第4、5个函数用于直接索引给定字符串。
    – 参数:域的名字和存储的值是两个最基本的属性。
    a. 域的名字:
    是相对固定的一个参数,用来指定添加域的标识,在检索时可以用来限定检索范围或提取属性值;
    b. 域存储的值:
    是一个必须的参数,使用形式包括 二进制(byte)串、Reader数据流 和 直接字符串 三种形式。
    更多时候,搜索引擎把一系列网页或文档的内容添加到索引中,使用Reader数据流的形式。
    Reader方式以流模式传送文件内容,便于使用和管理。
    c. 域的Store属性:
    表示数据本身是否需要存储,也就是说索引中是否要加一个原始数据项。
    支持三种类型的值:
    Store.NO(只存储索引,节省空间)
    Store.YES(同时保存索引和原始信息)
    Store.COMPRESS(压缩存储原始信息)
    d. 域的Index属性:
    表示数据是否需要索引,也就是当前域是否用来检索。
    Index支持四种属性:
    Index.NO(生成的域不需要索引,只是作为存储数据的单元提供辅助信息)
    Index.TOKENIZED(使用分析器分词来建立索引)
    Index.UN_TOKENIZED(如果某些内容系统整体作一个索引,避免分词带来的麻烦)
    Index.NO_NORMS(禁用分析器进行处理)
    e. Field.TermVector
    用来表示域内的信息是否需要分词,在中文信息搜索应用中,往往需要分词作为索引的基础。

    • lucene常见Field:
      IntField 主要对int类型的字段进行存储,需要注意的是如果需要对InfField进行排序使用SortField.Type.INT来比较,如果进范围查询或过滤,需要采用NumericRangeQuery.newIntRange()
      LongField 主要处理Long类型的字段的存储,排序使用SortField.Type.Long,如果进行范围查询或过滤利用NumericRangeQuery.newLongRange(),LongField常用来进行时间戳的排序,保存System.currentTimeMillions()
      FloatField 对Float类型的字段进行存储,排序采用SortField.Type.Float,范围查询采用NumericRangeQuery.newFloatRange()
      BinaryDocVluesField 只存储不共享值,如果需要共享值可以用SortedDocValuesField
      NumericDocValuesField 用于数值类型的Field的排序(预排序),需要在要排序的field后添加一个同名的NumericDocValuesField
      SortedDocValuesField 用于String类型的Field的排序,需要在StringField后添加同名的SortedDocValuesField
      StringField 用户String类型的字段的存储,StringField是只索引不分词
      TextField 对String类型的字段进行存储,TextField和StringField的不同是TextField既索引又分词
      StoredField 存储Field的值,可以用IndexSearcher.doc和IndexReader.document来获取此Field和存储的值

    5、索引项(Term):
    索引项是索引管理的最小的单位。
    在程序中没有显示的调用,是利用分析器,在后台自动把一个域的值进行分割。得到的每个独立元素作为一个索引项,用来建立索引。

    5.2.3 多文件索引结构:
    使用一系列索引文件分别存储索引,分散管理数据的索引存储格式。
    多文件索引在打开时需要读取大量的文件,会大大占用系统的文件句柄等资源,造成系统响应速度慢,甚至系统崩溃。
    在创建索引的过程中,使用IndexWriter的useCompoundfile属性来控制索引文件的类型。默认为true,保存成只包括3个文件的复合索引。
    如果希望采用多文件索引,必须调用SetUseCompoundFile(boolean)方法来指定,语法格式如下:
    - IndexWriter textIndex = new IndexWriter(Dest_Index_Path, TextAnalyzer, true);
    - textIndex.useCompoundFile(true);

    多文件格式包含了一系列的文件:
    - segments_* 文件:
    描述一组索引的参数,使用文件头固定格式描述后面的内容,包括每个独立新建索引的大小和属性等。
    - fnm 文件:
    是索引域描述文件。一个独立的索引(PerIndex)叫做一个Segment(索引段)。
    一个fnm文件描述了本索引的File数、各个Field的属性编号。
    - fdx文件:
    文档域值索引文件,采用定长方式存储,根据docId排序可以直接定位。
    用来记录每个文档的stord fields值的存储位置(文件偏移)
    - fdt文件:
    文档域值存储文件,存储stored field值的文件。
    通过fdx文件中记录的偏移来访问
    - tis文件:
    是存储每个term在文档中的分布信息,如文档频率、每个含term文档出现次数记录的偏移和位置记录的偏移排列顺序。
    先按Field名字字典排序,在每个Field按Term字典排序。
    - tii文件:
    是tis文件的索引和精简,排列格式是一致的,但是不包含每个term属性的信息,这个文件完全可以读入内存。
    - frq文件:
    是tis文件的扩展。记录每个term在每个文档中出现的频率。
    - prx文件:
    也是tis文件的延伸,记录每个term在每个文档偏移信息。这个文件忽略了docId,必须配合frq文件使用。
    - tvx、tvd、tvf文件:
    用来索引和保持每个文档的向量化字段的信息。

    5.2.4 复合索引结构:
    复合索引结构是把索引相关的一系列数据结构组织到少数几个文件中进行管理的索引存储模式。
    复合索引把所有的索引数据被组合成简单的3个文件,大大减少了打开大量文件的压力。
    但是使用统一文件存储大量数据会造成数据更新的问题,每次更改需要操作一个大的数据文件,读取和存储都会比较慢。
    复合索引文件格式:
    - segments_* 文件:
    描述一组索引的参数,使用文件头固定格式描述后面的内容,包括每个独立新建索引的大小和属性等。
    - segments_gen文件:
    存储索引创建参数。
    - cfs文件:
    存储实际的索引数据段,不同子索引在内部按照一定格式存储,仍然可以区分,知道索引优化压缩操作发生时。

    更多相关内容
  • 对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。例如索引是key index (a,b,c). 可以支持a | a,b| a,b,c 3种组合进行查找,但不支持 b,c进行查找 .当最左侧...

    对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。例如索引是key index (a,b,c). 可以支持a | a,b| a,b,c 3种组合进行查找,但不支持 b,c进行查找 .当最左侧字段是常量引用时,索引就十分有效。下面用几个例子对比查询条件的不同对性能影响.

    create table test(
    a int,
    b int,
    c int,
    KEY a(a,b,c)
    );
    优: select * from test where a=10 and b>50
    差: select * from test where a50
    
    优: select * from test where order by a
    差: select * from test where order by b
    差: select * from test where order by c
    
    优: select * from test where a=10 order by a
    优: select * from test where a=10 order by b
    差: select * from test where a=10 order by c
    
    优: select * from test where a>10 order by a
    差: select * from test where a>10 order by b
    差: select * from test where a>10 order by c
    
    优: select * from test where a=10 and b=10 order by a
    优: select * from test where a=10 and b=10 order by b
    优: select * from test where a=10 and b=10 order by c
    
    优: select * from test where a=10 and b=10 order by a
    优: select * from test where a=10 and b>10 order by b
    差: select * from test where a=10 and b>10 order by c

    索引原则

    1.索引越少越好
    原因:主要在修改数据时,第个索引都要进行更新,降低写速度。
    2.最窄的字段放在键的左边
    3.避免file sort排序,临时表和表扫描.

     

    于是上网查了下相关的资料:(关于复合索引优化的)

    两个或更多个列上的索引被称作复合索引。
    利 用索引中的附加列,您可以缩小搜索的范围,但使用一个具有两列的索引不同于使用两个单独的索引。复合索引的结构与电话簿类似,人名由姓和名构成,电话簿首 先按姓氏对进行排序,然后按名字对有相同姓氏的人进行排序。如果您知道姓,电话簿将非常有用;如果您知道姓和名,电话簿则更为有用,但如果您只知道名不 姓,电话簿将没有用处。
    所以说创建复合索引时,应该仔细考虑列的顺序。对索引中的所有列执行搜索或仅对前几列执行搜索时,复合索引非常有用;仅对后面的任意列执行搜索时,复合索引则没有用处。
    如:建立 姓名、年龄、性别的复合索引。

                                             

    复合索引的建立原则:

    如果您很可能仅对一个列多次执行搜索,则该列应该是复合索引中的第一列。如果您很可能对一个两列索引中的两个列执行单独的搜索,则应该创建另一个仅包含第二列的索引。
    如上图所示,如果查询中需要对年龄和性别做查询,则应当再新建一个包含年龄和性别的复合索引。
    包含多个列的主键始终会自动以复合索引的形式创建索引,其列的顺序是它们在表定义中出现的顺序,而不是在主键定义中指定的顺序。在考虑将来通过主键执行的搜索,确定哪一列应该排在最前面。
    请注意,创建复合索引应当包含少数几个列,并且这些列经常在select查询里使用。在复合索引里包含太多的列不仅不会给带来太多好处。而且由于使用相当多的内存来存储复合索引的列的值,其后果是内存溢出和性能降低。

             
    复合索引对排序的优化:

    复合索引只对和索引中排序相同或相反的order by 语句优化。
    在创建复合索引时,每一列都定义了升序或者是降序。如定义一个复合索引:

    Sql代码  

    CREATE INDEX idx_example   
    ON table1 (col1 ASC, col2 DESC, col3 ASC)  

    其中 有三列分别是:col1 升序,col2 降序, col3 升序。现在如果我们执行两个查询

    1:Select col1, col2, col3 from table1 order by col1 ASC, col2 DESC, col3 ASC

      和索引顺序相同

    2:Select col1, col2, col3 from table1 order by col1 DESC, col2 ASC, col3 DESC

     和索引顺序相反
    查询1,2 都可以别复合索引优化。
    如果查询为:

    Select col1, col2, col3 from table1 order by col1 ASC, col2 ASC, col3 ASC

      排序结果和索引完全不同时,此时的查询不会被复合索引优化。


    查询优化器在在where查询中的作用:

    如果一个多列索引存在于 列 Col1 和 Col2 上,则以下语句:Select   * from table where   col1=val1 AND col2=val2 查询优化器会试图通过决定哪个索引将找到更少的行。之后用得到的索引去取值。
    1. 如果存在一个多列索引,任何最左面的索引前缀能被优化器使用。所以联合索引的顺序不同,影响索引的选择,尽量将值少的放在前面。
    如:一个多列索引为 (col1 ,col2, col3)
        那么在索引在列 (col1) 、(col1 col2) 、(col1 col2 col3) 的搜索会有作用。

    Sql代码  

    SELECT * FROM tb WHERE  col1 = val1  
    SELECT * FROM tb WHERE  col1 = val1 and col2 = val2  
    SELECT * FROM tb WHERE  col1 = val1 and col2 = val2  AND col3 = val3  

     
    2. 如果列不构成索引的最左面前缀,则建立的索引将不起作用。
    如:

    Sql代码  

    SELECT * FROM  tb WHERE  col3 = val3  
    SELECT * FROM  tb  WHERE  col2 = val2  
    SELECT * FROM  tb  WHERE  col2 = val2  and  col3=val3  

     3. 如果一个 Like 语句的查询条件不以通配符起始则使用索引。
    如:%车 或 %车%   不使用索引。
        车%              使用索引。
    索引的缺点:
    1.       占用磁盘空间。
    2.       增加了插入和删除的操作时间。一个表拥有的索引越多,插入和删除的速度越慢。如 要求快速录入的系统不宜建过多索引。

    下面是一些常见的索引限制问题

    1、使用不等于操作符(<>, !=)
    下面这种情况,即使在列dept_id有一个索引,查询语句仍然执行一次全表扫描
    select * from dept where staff_num <> 1000;
    但是开发中的确需要这样的查询,难道没有解决问题的办法了吗?
    有!
    通过把用 or 语法替代不等号进行查询,就可以使用索引,以避免全表扫描:上面的语句改成下面这样的,就可以使用索引了。

    Sql代码  

    select * from dept shere staff_num < 1000 or dept_id > 1000;  

    2、使用 is null 或 is not null
    使 用 is null 或is nuo null也会限制索引的使用,因为数据库并没有定义null值。如果被索引的列中有很多null,就不会使用这个索引(除非索引是一个位图索引,关于位图 索引,会在以后的blog文章里做详细解释)。在sql语句中使用null会造成很多麻烦。
    解决这个问题的办法就是:建表时把需要索引的列定义为非空(not null)

    3、使用函数
    如果没有使用基于函数的索引,那么where子句中对存在索引的列使用函数时,会使优化器忽略掉这些索引。下面的查询就不会使用索引:

    Sql代码  

    select * from staff where trunc(birthdate) = '01-MAY-82';  

     但是把函数应用在条件上,索引是可以生效的,把上面的语句改成下面的语句,就可以通过索引进行查找。

    Sql代码  

    select * from staff where birthdate < (to_date('01-MAY-82') + 0.9999);  

    4、比较不匹配的数据类型
    比较不匹配的数据类型也是难于发现的性能问题之一。
    下面的例子中,dept_id是一个varchar2型的字段,在这个字段上有索引,但是下面的语句会执行全表扫描。

    Sql代码  

    select * from dept where dept_id = 900198;  

     这是因为oracle会自动把where子句转换成to_number(dept_id)=900198,就是3所说的情况,这样就限制了索引的使用。
    把SQL语句改为如下形式就可以使用索引

    Sql代码  

    select * from dept where dept_id = '900198';  

    还有就是参见 老王的blog上的文章

    http://hi.baidu.com/thinkinginlamp/blog/item/9940728be3986015c8fc7a85.html

    http://hi.baidu.com/thinkinginlamp/blog/item/a352918fe70d96fd503d925e.html

    http://blog.csdn.net/fbd2011/article/details/7341312

    http://blog.csdn.net/lovelyhermione/article/details/4580866

    1、普通索引

       普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。因此,应该只为那些最经常出现在查询条件 (WHEREcolumn=)或排序条件(ORDERBYcolumn)中的数据列创建索引。只要有可能,就应该选择一个数据最整齐、最紧凑的数据列(如 一个整数类型的数据列)来创建索引。

      2、唯一索引

      普通索引允许被索引的数据列包含重复的值。比如说,因为人有可能同名,所以同一个姓名在同一个“员工个人资料”数据表里可能出现两次或更多次。

       如果能确定某个数据列将只包含彼此各不相同的值,在为这个数据列创建索引的时候就应该用关键字UNIQUE把它定义为一个唯一索引。这么做的好处:一是 简化了MySQL对这个索引的管理工作,这个索引也因此而变得更有效率;二是MySQL会在有新记录插入数据表时,自动检查新记录的这个字段的值是否已经 在某个记录的这个字段里出现过了;如果是,MySQL将拒绝插入那条新记录。也就是说,唯一索引可以保证数据记录的唯一性。事实上,在许多场合,人们创建 唯一索引的目的往往不是为了提高访问速度,而只是为了避免数据出现重复。

      3、主索引

      在前面已经反复多次强调过:必须为主键字段创建一个索引,这个索引就是所谓的“主索引”。主索引与唯一索引的唯一区别是:前者在定义时使用的关键字是PRIMARY而不是UNIQUE。

      4、外键索引

      如果为某个外键字段定义了一个外键约束条件,MySQL就会定义一个内部索引来帮助自己以最有效率的方式去管理和使用外键约束条件。

      5、复合索引

       索引可以覆盖多个数据列,如像INDEX(columnA,columnB)索引。这种索引的特点是MySQL可以有选择地使用一个这样的索引。如果查 询操作只需要用到columnA数据列上的一个索引,就可以使用复合索引INDEX(columnA,columnB)。不过,这种用法仅适用于在复合索 引中排列在前的数据列组合。比如说,INDEX(A,B,C)可以当做A或(A,B)的索引来使用,但不能当做B、C或(B,C)的索引来使用。

      6、索引的长度

       在为CHAR和VARCHAR类型的数据列定义索引时,可以把索引的长度限制为一个给定的字符个数(这个数字必须小于这个字段所允许的最大字符个数)。 这么做的好处是可以生成一个尺寸比较小、检索速度却比较快的索引文件。在绝大多数应用里,数据库中的字符串数据大都以各种各样的名字为主,把索引的长度设 置为10~15个字符已经足以把搜索范围缩小到很少的几条数据记录了。在为BLOB和TEXT类型的数据列创建索引时,必须对索引的长度做出限 制;MySQL所允许的最大索引全文索引文本字段上的普通索引只能加快对出现在字段内容最前面的字符串(也就是字段内容开头的字符)进行检索操作。如果字 段里存放的是由几个、甚至是多个单词构成的较大段文字,普通索引就没什么作用了。这种检索往往以的形式出现,这对MySQL来说很复杂,如果需要处理的数 据量很大,响应时间就会很长。

       这类场合正是全文索引(full-textindex)可以大显身手的地方。在生成这种类型的索引时,MySQL将把在文本中出现的所有单词创建为一份 清单,查询操作将根据这份清单去检索有关的数据记录。全文索引即可以随数据表一同创建,也可以等日后有必要时再使用下面这条命令添加:

      ALTERTABLEtablenameADDFULLTEXT(column1,column2)有了全文索引,就可以用SELECT查询命令去检索那些包含着一个或多个给定单词的数据记录了。下面是这类查询命令的基本语法: 

     SELECT * FROMtablename WHEREMATCH(column1,column2)AGAINST(‘word1','word2','word3’)

      上面这条命令将把column1和column2字段里有word1、word2和word3的数据记录全部查询出来。

    附个实践(20万条数据):

    mysql -uroot -p123456
    
    use vlcmarket
    select count(*)from vlc_caiji_detail_1;
    select*from vlc_caiji_detail_1 where cid=934and days=3;
    0.09sec
    
    select*from vlc_caiji_detail_1 where cid=5and days=8;
    0.08sec
    
    
    索引:
    select*from vlc_caiji_detail_1 where cid=934and days=3;
    0.03
    select*from vlc_caiji_detail_1 where cid=5and days=8;
    0.02
    
    
    select*from vlc_caiji_detail_1 where cid=734and days=7;
    0.01
    select*from vlc_caiji_detail_1 where cid=30and days=1;
    0.01

    复合索引

    CREATE INDEX cid_days ON vlc_caiji_detail_1(cid, days);
    
    select*from vlc_caiji_detail_1 where cid=934and days=3;
    0.00sec
    
    select*from vlc_caiji_detail_1 where cid=5and days=8;
    0.00sec
    

    总结:复合索引最牛C,所以你懂的。。!

     

    索引分类:

    从数据结构角度

    1、B+树索引(O(log(n))):关于B+树索引,可以参考 MySQL索引背后的数据结构及算法原理

    2、hash索引:
    a 仅仅能满足"=","IN"和"<=>"查询,不能使用范围查询
    b 其检索效率非常高,索引的检索可以一次定位,不像B-Tree 索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以 Hash 索引的查询效率要远高于 B-Tree 索引
    c 只有Memory存储引擎显示支持hash索引

    3、FULLTEXT索引(现在MyISAM和InnoDB引擎都支持了)

    4、R-Tree索引(用于对GIS数据类型创建SPATIAL索引)

    从物理存储角度

    1、聚集索引(clustered index)

    2、非聚集索引(non-clustered index)

    从逻辑角度

    1、主键索引:主键索引是一种特殊的唯一索引,不允许有空值

    2、普通索引或者单列索引

    3、多列索引(复合索引):复合索引指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用复合索引时遵循最左前缀集合

    4、唯一索引或者非唯一索引

    5、空间索引:空间索引是对空间数据类型的字段建立的索引,MYSQL中的空间数据类型有4种,分别是GEOMETRY、POINT、LINESTRING、POLYGON。
    MYSQL使用SPATIAL关键字进行扩展,使得能够用于创建正规索引类型的语法创建空间索引。创建空间索引的列,必须将其声明为NOT NULL,空间索引只能在存储引擎为MYISAM的表中创建

    CREATE TABLE table_name[col_name data type]
    [unique|fulltext|spatial][index|key][index_name](col_name[length])[asc|desc]

    1、unique|fulltext|spatial为可选参数,分别表示唯一索引、全文索引和空间索引;

    2、index和key为同义词,两者作用相同,用来指定创建索引

    3、col_name为需要创建索引的字段列,该列必须从数据表中该定义的多个列中选择;

    4、index_name指定索引的名称,为可选参数,如果不指定,MYSQL默认col_name为索引值;

    5、length为可选参数,表示索引的长度,只有字符串类型的字段才能指定索引长度;

    6、asc或desc指定升序或降序的索引值存储

    展开全文
  • 复合索引文件格式cfs

    2010-05-22 13:25:00
    复合索引文件格式cfs 复合索引文件格式(.cfs)是如何产生的?从这个问题出发,研究索引文件是如何合并的,这都是IndexWriter类中定义的一些重要的方法。在建立索引过程中,生成的索引文件的格式有很多种。在文章 ...

    复合索引文件格式cfs

    复合索引文件格式(.cfs)是如何产生的?从这个问题出发,研究索引文件是如何合并的,这都是IndexWriter类中定义的一些重要的方法。

    在建立索引过程中,生成的索引文件的格式有很多种。

    在文章 Lucene-2.2.0 源代码阅读学习(4) 中测试的那个例子,没有对IndexWriter进行任何的客户化设置,完全使用Lucene 2.2.0默认的设置(以及,对Field的设置使用了Lucene自带的Demo中的设置)。

    运行程序以后,在本地磁盘的索引目录中生成了一些.扩展名为.cfs的索引文件,即复合索引格式文件。如图(该图在文章 Lucene-2.2.0 源代码阅读学习(4) 中介绍过)所示:

    从上面生成的那些.cfs复合索引文件可以看出,Lucene 2.2.0版本,IndexWriter索引的一个成员useCompoundFile的设置起了作用,可以在IndexWriter类的内部看到定义和默认设置:

    private boolean useCompoundFile = true;

    即,默认使用复合索引文件格式来存储索引文件。

    在IndexWriter类的addDocument(Document doc, Analyzer analyzer)方法中可以看到,最后调用了 maybeFlushRamSegments()方法,这个方法的作用可是很大的,看它的定义:

    protected final void maybeFlushRamSegments() throws CorruptIndexException, IOException {
        if (ramSegmentInfos.size() >= minMergeDocs || numBufferedDeleteTerms >= maxBufferedDeleteTerms) {
          flushRamSegments();
        }
    }

    这里,minMergeDocs是指:决定了合并索引段文件时指定的最小的Document的数量,在IndexWriter类中默认值为10,可以在IndexWriter类中查看到:

         private int minMergeDocs = DEFAULT_MAX_BUFFERED_DOCS;
       public final static int DEFAULT_MAX_BUFFERED_DOCS = 10;

    其中SegmentInfos ramSegmentInfos中保存了Document的数量的信息,如果Document的数量小于10,则调用flushRamSegments()方法进行处理,flushRamSegments()方法的定义如下所示:

    private final synchronized void flushRamSegments() throws CorruptIndexException, IOException {
        flushRamSegments(true);
    }

    在flushRamSegments()方法中又调用到了该方法的一个重载的方法,带一个boolean型参数。该重载的方法定义如下:

    protected final synchronized void flushRamSegments(boolean triggerMerge)
          throws CorruptIndexException, IOException {
        if (ramSegmentInfos.size() > 0 || bufferedDeleteTerms.size() > 0) {
          mergeSegments(ramSegmentInfos, 0, ramSegmentInfos.size());
          if (triggerMerge) maybeMergeSegments(minMergeDocs);
        }
    }

    同样,如果Document的数量小于10,则调用mergeSegments()方法,先看一下该方法的参数:

    private final int mergeSegments(SegmentInfos sourceSegments, int minSegment, int end)

    第一个参数指定了一个SegmentInfos(上面调用传递了ramSegmentInfos) ;第二个参数是minSegment是最小的索引段数量(上面调用传递了0,说明如果存在>=0个索引段文件时就开始合并索引文件);第三个参数是end,指要合并索引段文件的个数(上面调用传递了ramSegmentInfos.size(),即对所有的索引段文件都执行合并操作)。

    继续看mergeSegments()方法的实现:

    private final int mergeSegments(SegmentInfos sourceSegments, int minSegment, int end)
        throws CorruptIndexException, IOException {

        // doMerge决定了是否执行合并操作,根据end的值,如果end为0说明要合并的索引段文件为0个,即不需要合并,doMerge=false
        boolean doMerge = end > 0;

    /*    生成合并的索引段文件名称,即根据SegmentInfos的counter值,如果counter=0,则返回的文件名为_0(没有指定扩展名)

        final synchronized String newSegmentName() {
            return "_" + Integer.toString(segmentInfos.counter++, Character.MAX_RADIX);
        }

    */
        final String mergedName = newSegmentName();
        SegmentMerger merger = null;   // 声明一个SegmentMerger变量

        final List ramSegmentsToDelete = new ArrayList();    // ramSegmentsToDelete列表用于存放可能要在合并结束后删除的索引段文件,因为合并的过程中需要删除掉合并完以后存在于内存中的这些索引段文件

        SegmentInfo newSegment = null;

        int mergedDocCount = 0;
        boolean anyDeletes = (bufferedDeleteTerms.size() != 0);

        // This is try/finally to make sure merger's readers are closed:
        try {

          if (doMerge) {    // 如果doMerge=true,即end>0,也就是说至少有1个以上的索引段文件存在,才能谈得上合并
            if (infoStream != null) infoStream.print("merging segments");    // infoStream是一个PrintStream输出流对象,合并完成后要向索引目录中写入合并后的索引段文件,必须有一个打开的输出流
            merger = new SegmentMerger(this, mergedName);    // 构造一个SegmentMerger对象,通过参数:当前的打开的索引器this和合并后的索引段名称mergedName(形如_N,其中N为数)关于SegmentMerger类会在后面文章学习

            for (int i = minSegment; i < end; i++) {    // 循环遍历,从SegmentInfos sourceSegments中迭代出每个SegmentInfo对象
              SegmentInfo si = sourceSegments.info(i);
              if (infoStream != null)
                infoStream.print(" " + si.name + " (" + si.docCount + " docs)");    // SegmentInfo si的name在索引目录中是唯一的;这里打印出每个 SegmentInfo si的名称和在这个索引段文件中Document的数量
              IndexReader reader = SegmentReader.get(si, MERGE_READ_BUFFER_SIZE);   // 调用SegmentReader类的静态方法get(),根据每个SegmentInfo si获取一个索引输入流对象;在IndexWriter类中定义了成员MERGE_READ_BUFFER_SIZE=4096
              merger.add(reader);    //   将获取到的SegmentReader reader加入到SegmentMerger merger中
              if (reader.directory() == this.ramDirectory) {    // 如果SegmentReader reader是当前的索引目录,与当前的RAMDirectory ramDirectory是同一个索引目录
                ramSegmentsToDelete.add(si);    // 将该SegmentInfo si加入到待删除的列表ramSegmentsToDelete中
              }
            }
          }

          SegmentInfos rollback = null;
          boolean success = false;

          // This is try/finally to rollback our internal state
          // if we hit exception when doing the merge:
          try {

            if (doMerge) {     // 如果doMerge=true
              mergedDocCount = merger.merge();    // 通过SegmentMerger merger获取需要合并的索引段文件数量

              if (infoStream != null) {    // 打印出合并后的索引段文件的名称,及其合并了索引段文件的数量
                infoStream.println(" into "+mergedName+" ("+mergedDocCount+" docs)");
              }

              newSegment = new SegmentInfo(mergedName, mergedDocCount,
                                           directory, false, true);    // 实例化一个SegmentInfo对象
            }
           
            if (sourceSegments != ramSegmentInfos || anyDeletes) {
              // 通过克隆,存储一个用来回滚用的SegmentInfos实例,以防合并过程中发生异常
              rollback = (SegmentInfos) segmentInfos.clone();
            }

            if (doMerge) {   // 如果doMerge=true
              if (sourceSegments == ramSegmentInfos) {   // 如果传进来的sourceSegments和内存中的ramSegmentInfos是同一个
                segmentInfos.addElement(newSegment);    // 将合并后的新的SegmentInfo newSegment加入到segmentInfos中进行管理,以便之后再对其操作
              } else { // 如果传进来的sourceSegments和内存中的ramSegmentInfos不是同一个
                for (int i = end-1; i > minSegment; i--)     // 删除旧的信息,同时添加新的信息
                  sourceSegments.remove(i);

                segmentInfos.set(minSegment, newSegment);
              }
            }

            if (sourceSegments == ramSegmentInfos) {    // 如果传进来的sourceSegments和内存中的ramSegmentInfos是同一个,因为参数设置的原因,可能需要删除合并以后原来旧的索引段文件
              maybeApplyDeletes(doMerge);    // 调用 maybeApplyDeletes()方法执行合并后的删除处理
              doAfterFlush();
            }
           
            checkpoint();   // 调用该方法 checkpoint()检查,确认并提交更新

            success = true;    // 如果检查没有发现异常,则置success=true

          } finally {

            if (success) {    // 如果success=true,表示提交成功,要清理内存
              if (sourceSegments == ramSegmentInfos) {
                ramSegmentInfos.removeAllElements();
              }
            } else {    // 如果发生异常,则需要回滚操作

              if (sourceSegments == ramSegmentInfos && !anyDeletes) {
                if (newSegment != null &&
                    segmentInfos.size() > 0 &&
                    segmentInfos.info(segmentInfos.size()-1) == newSegment) {
                  segmentInfos.remove(segmentInfos.size()-1);
                }
              } else if (rollback != null) {
                segmentInfos.clear();
                segmentInfos.addAll(rollback);
              }

              // Delete any partially created and now unreferenced files:
              deleter.refresh();
            }
          }
        } finally {
          // 关闭所有的输入流(readers),尝试删除过时的废弃文件
          if (doMerge) merger.closeReaders();
        }

        // 删除RAM中的索引段文件
        deleter.deleteDirect(ramDirectory, ramSegmentsToDelete);

        // 一个检查点,允许一个IndexFileDeleter deleter有机会在该时间点上去删除文件
        deleter.checkpoint(segmentInfos, autoCommit);

        if (useCompoundFile && doMerge) {   // 如果IndexWriter索引器设置了useCompoundFile=true

          boolean success = false;

          try {

            merger.createCompoundFile(mergedName + ".cfs");    //   创建复合索引文件(.cfs),即_N.cfs文件
            newSegment.setUseCompoundFile(true);    // 设置SegmentInfo newSegment为复合索引文件的信息
            checkpoint();      // 调用该方法 checkpoint()检查,确认并提交更新
            success = true;

          } finally {    // 如果检查过程中发生异常,则回滚
            if (!success) {  
              newSegment.setUseCompoundFile(false);
              deleter.refresh();
            }
          }
          
         // 一个检查点,允许一个IndexFileDeleter deleter有机会在该时间点上去删除文件
          deleter.checkpoint(segmentInfos, autoCommit);
        }

        return mergedDocCount; // 返回需合并的索引段文件数量
    }

     

     

     

     

     

     

     

     

     

    在不带参数的flushRamSegments()方法中,调用了带参数的flushRamSegments(boolean triggerMerge),也就是说,默认情况下,Lucene指定triggerMerge=true,可以在不带参数的flushRamSegments()方法中看到对该参数的设置:

    private final synchronized void flushRamSegments() throws CorruptIndexException, IOException {
        flushRamSegments(true);
    }

    所以,在带参数的flushRamSegments(boolean triggerMerge)方法中,一定会执行maybeMergeSegments()这个合并索引的方法,如下所示:

    if (triggerMerge) maybeMergeSegments(minMergeDocs);

    这里,传递的参数minMergeDocs=10(Lucene默认值),那么就应该有一个maxMergeDocs的成员与之对应,在Lucene 2.2.0版本中,在IndexWriter类中定义了该maxMergeDocs成员的默认值:

        private int maxMergeDocs = DEFAULT_MAX_MERGE_DOCS;
        public final static int DEFAULT_MAX_MERGE_DOCS = Integer.MAX_VALUE;
        public static final int   MAX_VALUE = 0x7fffffff;

    maxMergeDocs是合并的最大的Document的数量,定义为最大的Integer。

    因为一个索引目录中的索引段文件的数量可能大于minMergeDocs=10,如果也要对所有的索引段文件进行合并,则指定合并最小数量minMergeDocs的Docment是不能满足要求的,即使用mergeSegments()方法。

    因此,maybeMergeSegments()就能实现合并性能的改善,它的声明就是需要一个起始的参数,从而进行增量地合并索引段文件。该方法的实现如下所示:

    /** Incremental segment merger. */
    private final void maybeMergeSegments(int startUpperBound) throws CorruptIndexException, IOException {
        long lowerBound = -1;
        long upperBound = startUpperBound;    // 使用upperBound存放传递进来的startUpperBound

        while (upperBound < maxMergeDocs) {    // 如果upperBound < maxMergeDocs,一般来说,这个应该总成立的
          int minSegment = segmentInfos.size();    //   设置minSegment的值为当前的SegmentInfos segmentInfos 的大小
          int maxSegment = -1;

          // 查找能够合并的索引段文件
          while (--minSegment >= 0) {    // 就是遍历SegmentInfos segmentInfos中的每个SegmentInfo si
            SegmentInfo si = segmentInfos.info(minSegment);    // 从索引位置号最大的开始往外取

            if (maxSegment == -1 && si.docCount > lowerBound && si.docCount <= upperBound) {    // maxSegment == -1;同时满足-1=lowerBound <(一个索引段文件中Dcoment的数量si.docCount)<=upperBound = startUpperBound
              // start from the rightmost* segment whose doc count is in bounds
              maxSegment = minSegment;    //   设置maxSegment的值为当前SegmentInfos的大小
            } else if (si.docCount > upperBound) {
              // 直到segment中Document的数量超过了上限upperBound,则退出循环
              break;
            }
          }

        // 该while循环只执行了一次,执行过程中,将maxSegment赋值为segmentInfos.size()-1

          minSegment++;    // 上面循环中一直执行--minSegment,则到这里minSegment=-1,设置其值为0
          maxSegment++;    // 因为maxSegment=segmentInfos.size()-1,则设置为maxSegment=segmentInfos.size()
          int numSegments = maxSegment - minSegment;    // numSegments = maxSegment - minSegment = segmentInfos.size()  

          if (numSegments < mergeFactor) {

        /* mergeFactor是合并因子,IndexWriter的成员,默认设置为10,mergeFactor的值越大,则内存中驻留的Document就越多,向索引目录中写入segment的次数就越少,虽然占用内存较多,但是速度应该很快的。每向索引文件中加入mergeFactor=10个Document的时候,就会在索引目录中生成一个索引段文件(segment) */
            break;    // numSegments < mergeFactor则没有达到合并所需要的数量,不需要合并,直接退出
          } else {
            boolean exceedsUpperLimit = false;    // 设置一个没有超过上限的boolean型标志(false)

            // 能够合并的segments的数量>=mergeFactor时
            while (numSegments >= mergeFactor) {
              // 调用mergeSegments(即上面的学习到的那个合并的方法)方法,合并从minSegment开始的mergeFactor个segment

              int docCount = mergeSegments(segmentInfos, minSegment, minSegment + mergeFactor);
              numSegments -= mergeFactor; // mergeFactor个segment已经合并完成,剩下需要合并的数量要减去mergeFactor,在下一次循环的时候继续合并

              if (docCount > upperBound) {    // 如果上次合并返回的合并后的Document的数量大于上限
                // 继续在该层次合并剩余的segment
                minSegment++;
                exceedsUpperLimit = true;    //   设置已经超过上限,不能再进行深一层次的的合并,即本轮合并就是最深层次的合并了
              } else { // 如果上次合并返回的合并后的Document的数量没有超过上限
                // 考虑进行更深层次的合并
                numSegments++;
              }
            }

            if (!exceedsUpperLimit) {// 如果上次合并返回的合并后的Document的数量大于上限,则终止执行本层次合并
              break;
            }
          }

          lowerBound = upperBound;
          upperBound *= mergeFactor;    // 如果一个层次的合并成功后,还可以进一步合并,则,上限变为原来的10倍
        }
    }

    合并索引段文件就是这样实现的,并非只是在一个层次上合并:

    第一层次合并时,每次只能将10个segment索引段文件合并为1个新的segment,假设在这一层生成了500个经过合并以后生成的索引段文件;

    第二层次合并时,每次能合并10*mergeFactor=10*10=100个segment,经判断,上一层次生成了500个segment还可以进行第二层次的合并,现在每次100个segment文件才可能合并为1个,可见,只能合并生成5个新的segment;

    第三层次合并时,每次能合并10*mergeFactor*mergeFactor=10*10*10=1000个segment,但是上一层次只是生成了5个,不够数量(1000个),不能继续合并了,到此终止。

    就是上面的那种原理,实现索引段文件的合并。如果希望进行更深层次的合并,把mergeFactor的值设置的非常小就可以了,但是I/O操作过于频繁,速度会很慢很慢的。

    提高合并的速度,是以内存空间开销为代价的。

    通过第一个合并的方法可以看出,只有当为一个IndexWriter索引器设置了useCompoundFile=true的时候,才能生成复合索引文件_N.cfs,如下所示:

        if (useCompoundFile && doMerge) {   // 如果IndexWriter索引器设置了useCompoundFile=true

          boolean success = false;

          try {

            merger.createCompoundFile(mergedName + ".cfs");    //   创建复合索引文件(.cfs),即_N.cfs文件
            newSegment.setUseCompoundFile(true);    // 设置SegmentInfo newSegment为复合索引文件的信息
            checkpoint();      // 调用该方法 checkpoint()检查,确认并提交更新
            success = true;

          } finally {    // 如果检查过程中发生异常,则回滚
            if (!success) {  
              newSegment.setUseCompoundFile(false);
              deleter.refresh();
            }
          }
          
         // 一个检查点,允许一个IndexFileDeleter deleter有机会在该时间点上去删除文件
          deleter.checkpoint(segmentInfos, autoCommit);
        }

    现在知道了,那些_N.cfs文件是合并的索引段文件。

    展开全文
  • lucene 索引文件格式

    千次阅读 2015-04-21 21:22:16
    下图是一个典型的Lucene4.x的索引结构图:  Lucene4.x之后的所有索引格式如下所示:  文件名 后缀 描述 Segments File segments.gen, segments_N 存储段文件的提交点...

    下图是一个典型的Lucene4.x的索引结构图: 


    Lucene4.x之后的所有索引格式如下所示: 

    文件名 后缀 描述
    Segments File segments.gen, segments_N 存储段文件的提交点信息
    Lock File write.lock 文件锁,保证任何时刻只有一个线程可以写入索引
    Segment Info .si 存储每个段文件的元数据信息
    Compound File .cfs, .cfe 复合索引的文件,在系统上虚拟的一个文件,用于频繁的文件句柄
    Fields .fnm 存储域文件的信息
    Field Index .fdx 存储域数据的指针
    Field Data .fdt 存储所有文档的字段信息
    Term Dictionary .tim term字典,存储term信息
    Term Index .tip term字典的索引文件
    Frequencies .frq 词频文件,包含文档列表以及每一个term和其词频
    Positions .prx 位置信息,存储每个term,在索引中的准确位置
    Norms .nrm.cfs, .nrm.cfe 存储文档和域的编码长度以及加权因子
    Per-Document Values .dv.cfs, .dv.cfe 编码除外的额外的打分因素,
    Term Vector Index .tvx term向量索引,存储term在文档中的偏移距离
    Term Vector Documents .tvd 包含每个文档向量的信息
    Term Vector Fields .tvf 存储filed级别的向量信息
    Deleted Documents .del 存储索引删除文件的信息


    复合索引文件是指,除了段信息文件,锁文件,以及删除的文件外,其他的一系列索引文件压缩一个后缀名为cfs的文件,意思,就是所有的索引文件会被存储成一个单例的Directory,而非复合索引是灵活的,可以单独的访问某几个索引文件,而复合索引文件则不可以,因为其压缩成了一个文件,所以在某些场景下能够获取更高的效率,比如说,查询频繁,而不经常更新的需求,就很适合这种索引格式。      

    lucene索引的基本概念组成由,索引,文档,域和项组成,一个索引,通常包含一些序列的文档,一个文档包含一些序列的域,而一些域又包含一些序列的项,而一些项则包含一些列序列的最低层的字节,注意这里的序列指的是在索引结构中有序,通常有序的这种方式,某些情况可以优化索引结构。 


    lucene使用了倒排索引(Inverted Indexing),来存储索引信息,大大提高了检索效率, 
    倒排索引,举一个通俗的例子,原来基于人们的正常思维,我们会存储的是一个文章中出现了那几个单词,而倒排索引,却恰恰相反,它存储的是这个单词,包含在几个文档中,当然这个关系是由倒排链表(存储一系列docid)构成的索引,我们在检索时,通过这个单词可以快速的定位,它出现在几篇文章中,从而大大提升了检索性能。 

    当然lucene中不仅仅有倒排索引,也有正向的存储,而倒排之所以是lucene的核心,是因为它提升了检索性能,在检索到一个个具体的文档时,就需要我们正向的拿出这些信息,反映在实际的代码中就是我们通过检索获取一个个docid,然后通过一个个docid获取整个文档,然后我们在正向的获取各个域,以及各个项存储的具体信息,当然前提是你存储了这个字段,如果你只是索引了,而并没有存储,那么你只能检索到此条信息,但无法获取具体term的值,这个需要在建索引之前就要设计好,索引的存储结构,那些字段是检索的,那些字段是存储的等等,如果你还需要高亮一些内容,则还需要存储这个域的偏移的位置,通过这样就能准确的在文中标记检索命中的关键词,如果你打算在前台来完成这个高亮,就不要存储这些信息了。 


    转自: http://my.oschina.net/MrMichael/blog/220961

    展开全文
  • 索引相关概念聚簇索引(clustered index)使用innodb引擎时,每张表都有一个聚簇索引,比如我们设置的主键就是聚簇索引聚簇是指数据的存储方式,表示数据行和相邻的键值紧凑的储存在一起特点:查询数据特别快,因为聚...
  • 另外VF中各62616964757a686964616fe58685e5aeb931333433643137种文件扩展名:.pjx 项目.pjt 项目备注.dbc 数据库.frx 报表.frt 报表备注.lbx 标签.prg 程序.dct 数据库备注.dcx 数据库索引.dbf 表.fpt 表备注.cdx ...
  • 1.为什么要使用索引索引是什么? 这里很官方的回答是:索引是帮助 MySQL 高效获取数据的数据结构。 索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。 数据库...
  • Lucene深入学习(8)Lucene的索引文件

    千次阅读 2017-11-30 23:54:56
    生成索引文件使用最简洁的代价生成一组索引文件。 IndexWriter writer = null; Directory directory = FSDirectory.open(Paths.get("d://myindex")); IndexWriterConfig config = new IndexWriterConfig(); ...
  • MySQL索引介绍

    2022-02-21 11:27:26
    一、索引简介 1、索引是什么? MySQL官方对索引的定义:索引(Index)是帮助MySQL高效获取数据...因此,首先你要明白的一点就是,索引它也是一个文件,它是要占据物理空间的。 比如对于MyISAM存储引擎来说: ....
  • } 以上是我在开发过程中的实例,刚开始我导出的Excel格式后缀名是用“xlsx”,后面测试人员本地电脑用了电脑自带的office工具,无法打开,我在开发电脑上用的是WPS编辑都正常所以没发现这个问题, 刚开始想到的是...
  • lucene 索引文件简介

    2014-08-20 15:47:45
    由上文中提到的代码生成的索引文件如下所示:     格式都相当怪异,那些这些文件里面都存放了些什么东西?我们先来了解如下名词 a) 段信息(SegmentInfo):它包含段的元数据; b) 字段...
  • 在lucene4.x中,lucene的索引文件的几种格式,以及它们的作用和结构。   下图是一个典型的Lucene4.x的索引结构图:    Lucene4.x之后的所有索引格式如下所示:  文件名 后缀 描述 Segments ...
  • 索引文件介绍与数据类型

    千次阅读 2017-09-20 21:43:51
    Lucene生成的索引文件 由上文中提到的代码生成的索引文件如下所示: 格式都相当怪异,那些这些文件里面都存放了些什么东西?我们先来了解如下名词 a)段信息(SegmentInfo):它包含段的元数据; b)字段(Field...
  • MySQL中Innodb的索引

    2020-06-08 03:17:18
    索引是存储引擎用于快速找到记录的一种数据结构,索引往往以索引文件的形式存储的磁盘上。 索引总结下来有如下几个优点: 1.索引大大减少了服务器需要扫描的数据量,提高查询性能。 2.素引可以帮助服务器避免...
  • MySQL单列索引和组合索引的区别

    千次阅读 2017-02-05 20:44:48
    下文形象地对比了MySQL单列索引和组合索引的区别,希望可以让您对这两种索引有更深的认识。   MySQL单列索引和组合索引的区别可能有很多人还不是十分的了解,下面就为您分析两者的主要区别,供您参考学
  • Lucene文件扩展名

    2014-01-01 10:41:00
    文件后缀 描述 段文件(Segments File) segments.gen segments_N 存储提交点信息 锁文件(Lock File) write.lock 用来阻止多个indexWriter向同一个文件写数据 ...
  • 文件后缀名 解析 说明 Segments File segments.gen segments_N 存储段文件的提交点信息   Lock File write.lock 文件锁,保证任何时刻只有一个线程可以写入索引   ...
  • Hash索引和B+tree索引的区别 应用场景 索引分类 普通索引 创建单列索引——普通索引(3种语法) 查看数据库中的索引 查看数据表中的索引 删除索引 唯一索引 主键索引 组合索引 创建和删除组合索引 全文...
  • 本文会图解两种引擎的索引结构区别,然后讲解索引的原理,理解本文内容,就能够理解索引优化的各种原则的背后原因。限于篇幅,本篇没有介绍的知识,会在后续博客将逐一讲解。例如:MySQL引擎的锁机制、多列索引的...
  • SQL语句-创建索引

    2021-02-04 21:02:16
    语法:CREATE [索引类型] INDEX 索引名称ON 表名(列名)WITH FILLFACTOR = 填充因子值0~100GOUSE 库名GOIF EXISTS (SELECT * FROM SYSINDEXES WHERE NAME='IX_TEST_TNAME')--检测是否已经存在IX_TEST_TNAME索引DROP ...
  • lucene索引文件格式详解   本文介绍lucene中segment,.fnm,.fdx,.fdt,.tii,.tis,deletable ,.cfs等格式文件的用途。 1。索引的segment 每个segment代表lucene的一个完整索引段。通常,在一个索引中,会包含有...
  • 单项选择题1.在一个表中可以建立( )A) 多个普通索引,多个唯一索引,多个候选索引,一个主索引B) 一个普通索引,多个唯一索引,多...表xsda.bdf中结构复合索引文件名可为( )A) xsda.idxB) xsda.cdxC) sy.idxD) sy.cd...
  • lucene-索引文件格式

    2013-05-30 10:35:39
    3.1 索引文件结构 ... Lucene使用文件扩展名标识不同的索引文件,文件名标识不同版本或者代(generation)的索引片段(segment)。如.fnm文件存储域Fields名称及其属性,.fdt存储文档各项域数据
  • MySQL单列索引和组合索引的区别介绍

    千次阅读 2013-12-26 19:59:03
    MySQL单列索引是我们使用MySQL数据库中经常会见到的,MySQL单列索引和组合索引的区别可能有很多人还不是十分的了解,下面就为您分析两者的主要区别,供您参考学习。  为了形象地对比两者,再建一个表: ...
  • 索引文件结构

    2012-06-04 18:30:44
    Lucene使用文件扩展名标识不同的索引文件,文件名标识不同版本或者代(generation)的索引片段(segment)。如.fnm文件存储域Fields名称及其属性,.fdt存储文档各项域数据,.fdx存储文档在fdt中的偏移位置即其索引...
  • 向量的索引文件格式

    2016-12-25 12:32:00
    Normalization factors(归一化因数,文件后缀名为.nrm),每个文档的每个字段都会被存储,在检索的时候这个归一化因素会被与标准得分相乘得到最终的评分,存储的格式以DocValues的格式存储进去。 归一化基数在...
  • Office 文档(如:.doc、.ppt、.xls等)很多是复合文档(OLE文件),所有文件数据都是存储在一个或多个流中。每 个流都有一个相似的数据结构,用于存储元数据的数据结构。这些元数据有用户和系统的信息、文件属性、...
  • 介绍了Lucene里面所有的文件格式以及的作用,那么接下来的一系列文章里,将逐个细说,今天我们先来看下lucene索引文件格式里面的老大段文件,以.gen ,.si为后缀名的文件。 .si是记录段文件的元数据的信息,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 22,186
精华内容 8,874
关键字:

复合索引文件扩展名