# Basics of Manticore Indexes

本文将介绍Manticore索引的基础知识。

Manticore Search支持两种存储索引类型：


 - 普通索引（也称为离线或磁盘索引）。数据在创建时一次性索引，它支持非文本属性的在线重建和在线更新

 - 实时索引。类似于数据库表，可以在任何时间进行在线更新



此外，还有一种基于实时索引类型的特殊索引，称为 <cite>percolate</cite>，可用于存储 [<span class="std std-ref">Percolate Queries</span>](https://docs.manticoresearch.com/latest/html/searching/percolate_query.html#percolate-query)。

在当前版本中，索引使用类似于普通数据库表的模式。该模式可以有3种主要类型的列：

 - 第一列始终是无符号64位非零数字，称为 <cite>id</cite>。与数据库不同，没有自动递增机制，因此需要确保文档id是唯一的

 - 全文字段 - 它们包含索引内容。每个索引可以有多个全文字段。可以在所有字段或选择性字段上进行全文搜索。目前原始文本不会被存储，如果需要在搜索结果中显示其内容，必须使用搜索结果提供的id（或其他标识符）访问原始源

 - 属性 - 它们的值被存储，但不用于全文匹配。相反，它们可以用于常规过滤、分组、排序。它们也可以用于评分排序的表达式中。



属性中可以存储以下数据类型：

 - 无符号32位和有符号64位整数

 - 32位单精度浮点数

 - UNIX时间戳

 - 布尔值

 - 字符串

 - JSON对象

 - 无符号32位整数或有符号64位整数的多值属性列表



Manticore Search支持一种称为分布式索引的无存储索引类型，允许在多个索引上进行搜索。连接的索引可以是本地或远程的。分布式索引允许将大数据分布在多台机器上或构建高可用性设置。

另一种无存储索引类型是 [模板](https://docs.manticoresearch.com/latest/html/indexing/indexes.html#templates-indexes)。模板索引不存储数据，但可以保存分词设置，如带有存储的索引。它可以用于测试分词规则或生成高亮显示。

  
  
普通索引
----------

---



除了数值（包括MVA）属性外，普通索引中的其余数据是不可变的。如果需要更新/添加新记录，需要再次执行重建。在索引重建期间，现有索引仍然可用以处理请求。当新版本准备就绪时，会执行一个称为 <cite>轮换</cite> 的过程，将新版本上线并丢弃旧版本。

索引性能过程取决于多个因素：

 - 数据源提供数据的速度

 - 分词设置

 - 硬件资源（CPU性能、存储速度）



在最简单的使用场景中，我们会使用一个普通索引，并定期重建它。

这意味着：

 - 索引的数据更新不及时

 - 索引时间随着数据量增长而增加



如果我们希望数据更新更及时，需要缩短索引间隔。如果索引时间过长，甚至可能与索引间隔时间重叠，这会是一个主要问题。然而，Manticore Search可以在多个索引上执行搜索。由此产生了使用一个次要索引的想法，该索引仅捕获最近的更新。

这个索引会小得多，我们会更频繁地对其进行索引。随着时间的推移，当这个增量索引增长时，我们希望“重置”它。

这可以通过重新索引主索引或将增量合并到主索引中来完成。主索引+增量索引的模式在 [<span class="std std-ref">Delta索引更新</span>](https://docs.manticoresearch.com/latest/html/indexing/delta_index_updates.html#delta-index-updates) 中详细说明。

由于引擎无法全局对文档id进行唯一性检查，需要考虑的一个重要问题是增量索引是否可能包含主索引中现有记录的更新。

为此，有一个选项允许定义由增量索引抑制的文档id列表。更多细节，请查看 [<span class="std std-ref">sql_query_killlist</span>](https://docs.manticoresearch.com/latest/html/conf_options_reference/data_source_configuration_options.html#sql-query-killlist)。



  
  
实时索引
--------------

---



[实时索引](https://docs.manticoresearch.com/latest/html/real-time_indexes.html) 允许在线更新，但更新全文数据和非数值属性需要进行完整的行替换。

实时索引最初是空的，您可以像数据库表一样添加、替换、更新或删除数据。更新首先保存到内存区域（称为RAM块），由 [<span class="std std-ref">rt_mem_limit</span>](https://docs.manticoresearch.com/latest/html/conf_options_reference/index_configuration_options.html#rt-mem-limit) 定义。当该区域填满时，它会被转储为磁盘块 - 其结构与普通索引类似。随着磁盘块数量的增加，搜索性能会下降，因为搜索是按顺序在块上进行的。为了解决这个问题，需要将块合并为一个，这通过 [<span class="std std-ref">OPTIMIZE INDEX</span>](https://docs.manticoresearch.com/latest/html/sphinxql_reference/optimize_index_syntax.html#optimize-index-syntax) 命令完成。

RAM块也可以通过 [FLUSH RAMCHUNK](https://docs.manticoresearch.com/latest/html/sphinxql_reference/flush_ramchunk_syntax.html) 强制转储到磁盘。在刷新RAM块并优化索引后，RT索引的性能最佳 - RT索引将所有数据存储在一个块中，并具有与普通索引相同的性能。

通过两种方式可以填充 RealTime 索引：触发 INSERT 或 [转换](https://docs.manticoresearch.com/latest/html/sphinxql_reference/attach_index_syntax.html) 一个普通索引成为 RealTime。现有数据可以通过逐条插入或批量插入多个记录到单个插入中。多个并行插入数据的工作线程将加快进程，但会使用更多 CPU。

RAM 块大小会影响更新速度，更大的 RAM 块将提供更好的性能，但需要根据可用内存进行调整。还必须注意，rt_mem_limit 仅限制 RAM 块的大小。磁盘块（基本上是普通索引）将有自己的内存需求（用于加载字典或属性）。

RAM 块的内容会在干净关闭期间或定期写入磁盘，由 [rt_flush_period](https://docs.manticoresearch.com/latest/html/conf_options_reference/searchd_program_configuration_options.html#rt-flush-period) 指令定义（可以通过 FLUSH RTINDEX 命令强制执行）。RT 索引也可以使用 [二进制日志](https://docs.manticoresearch.com/latest/html/real-time_indexes.html#binary-logging) 来记录更改。在守护进程启动时可以重放 binlog 以恢复非干净关闭后的数据，并在 RAM 块刷新到磁盘后清除 binlog。

binlog 刷新 [策略](https://docs.manticoresearch.com/latest/html/conf_options_reference/searchd_program_configuration_options.html#binlog-flush)（类似于 MySQL 的 innodb_flush_log_at_trx_commit）可能会影响性能。binlog 也可以通过设置空的 binlog 路径来禁用，但这会使未刷新到磁盘的更新没有保护。



  
  
本地分布式索引
----------------------

---



Manticore Search 中的分布式索引不存储任何数据。相反，它作为“主节点”在其他索引上触发所需查询，并从“节点”索引接收到的响应中提供合并结果。分布式索引可以连接到本地索引或位于其他服务器上的索引。在我们的情况下，分布式索引将如下所示：



```bash
index_dist {
  type = distributed
  local = index1
  local = index2
  ...
 }

```



启用多核搜索的最后一步是在 searchd 部分定义 dist_threads。dist_threads 告诉引擎分布式索引可以使用的最大线程数。



  
  
远程分布式索引和高可用性
---------------------------------------------

---






```bash
index mydist {
          type = distributed
          agent = box1:9312:shard1
          agent = box2:9312:shard2
          agent = box3:9312:shard3
          agent = box4:9312:shard4
}

```



在这里，我们将数据分布在 4 台服务器上，每台服务器提供一个分片。如果其中一台服务器发生故障，我们的分布式索引仍将工作，但我们会丢失故障分片的结果。



```bash
index mydist {
          type = distributed
          agent = box1:9312|box5:9312:shard1
          agent = box2:9312:|box6:9312:shard2
          agent = box3:9312:|box7:9312:shard3
          agent = box4:9312:|box8:9312:shard4
}

```



现在我们添加了镜像，每个分片在 2 台服务器上都有副本。默认情况下，主节点（带有分布式索引的 searchd 实例）将随机选择一个镜像。

选择镜像的模式可以通过 ha_strategy 设置。除了随机选择，另一种简单的方法是进行轮询选择（ha_strategy= roundrobin）。

更有意思的策略是基于延迟加权概率的策略。noerrors 和 nodeads 不仅会移除有问题的镜像，还会监控响应时间并进行平衡。如果某个镜像响应较慢（例如由于其上运行了某些操作），它将收到较少的请求。当镜像恢复并提供更好的响应时间时，它将收到更多的请求。
