Manticore Search 2.x 保持与 Sphinxsearch 2.x 的兼容性,可以加载由 Sphinxsearch 创建的现有表。在大多数情况下,升级只是替换二进制文件的问题。
Manticore 默认使用 /etc/manticoresearch/manticore.conf,而不是 sphinx.conf(在 Linux 中通常位于 /etc/sphinxsearch/sphinx.conf)。它还以不同的用户身份运行,并使用不同的文件夹。
Systemd 服务名称已从 sphinx/sphinxsearch 更改为 manticore,服务以用户 manticore 运行(Sphinx 使用的是 sphinx 或 sphinxsearch)。它还使用不同的文件夹存放 PID 文件。
默认使用的文件夹是 /var/lib/manticore、/var/log/manticore、/var/run/manticore。你仍然可以使用现有的 Sphinx 配置,但需要手动更改 /var/lib/sphinxsearch 和 /var/log/sphinxsearch 文件夹的权限。或者,直接在系统文件中全局将 'sphinx' 重命名为 'manticore'。如果你使用其他文件夹(用于数据、词形文件等),所有权也必须切换为用户 manticore。pid_file 位置应更改为与 manticore.service 匹配,即 /run/manticore/searchd.pid。
如果你想使用 Manticore 文件夹,则需要将表文件移动到新的数据文件夹(/var/lib/manticore),并将权限更改为用户 manticore。
从 Sphinx / Manticore 2.x 升级到 3.x 并不简单,因为表存储引擎经历了重大升级,新的 searchd 无法加载旧表并即时升级到新格式。
Manticore Search 3 重新设计了表存储。使用 Manticore/Sphinx 2.x 创建的表无法被 Manticore Search 3 加载,除非进行转换。由于 4GB 限制,2.x 中的实时表在优化操作后仍可能有多个磁盘块。升级到 3.x 后,这些表可以通过常规的 OPTIMIZE 命令优化为单磁盘块。索引文件也发生了变化。唯一未发生结构变化的组件是 .spp 文件(命中列表)。.sps(字符串/json)和 .spm(MVA)现在由 .spb(变长属性)持有。新格式中存在 .spm 文件,但它用于行映射(之前专用于 MVA 属性)。新增的扩展名有 .spt(docid 查找)、.sphi(二级索引直方图)、.spds(文档存储)。如果你使用脚本操作表文件,应适配新的文件扩展名。
升级过程可能因你的设置(集群中服务器数量、是否有高可用等)而异,但通常涉及创建新的 3.x 表版本并替换现有表,以及用新二进制文件替换旧的 2.x 文件。
有两个特殊要求需要注意:
- 实时表需要使用 FLUSH RAMCHUNK 刷新
- 带有 kill-list 的普通表需要在表配置中添加新指令(参见 killlist_target)
Manticore Search 3 包含一个新工具 - index_converter - 可以将 Sphinx 2.x / Manticore 2.x 表转换为 3.x 格式。index_converter 是一个单独的软件包,需要先安装。使用转换工具创建表的 3.x 版本。index_converter 可以将新文件写入现有数据文件夹并备份旧文件,或者写入指定文件夹。
如果你只有一台服务器:
- 安装 manticore-converter 软件包
- 使用 index_converter 在不同于现有数据文件夹的文件夹中创建表的新版本(使用
--output-dir选项) - 停止现有的 Manticore/Sphinx,升级到 3.0,将新表移动到数据文件夹,然后启动 Manticore
为了最小化停机时间,你可以复制 2.x 表、配置(需要编辑表、日志路径和不同端口)、二进制文件到另一个位置,并在不同端口启动。将应用程序指向它。升级到 3.0 并启动新服务器后,可以将应用程序指回正常端口。如果一切正常,停止 2.x 副本并删除文件以释放空间。
如果你有备用机器(如测试或预发布服务器),可以先在那里进行表升级,甚至安装 Manticore 3 进行多次测试。如果一切正常,将新表文件复制到生产服务器。如果你有多台服务器可以从生产环境中抽出,逐台进行升级。对于分布式设置,2.x searchd 可以作为主节点与 3.x 节点共存,因此可以先升级数据节点,再升级主节点。
客户端连接引擎的方式、查询模式或查询行为没有任何变化。
Kill-list 在 Manticore Search 3 中进行了重新设计。在之前的版本中,kill-list 在查询时应用于每个先前搜索表提供的结果集。
因此,在 2.x 中,查询时表的顺序很重要。例如,如果增量表有 kill-list,为了对主表应用它,顺序必须是主表、增量表(无论是在分布式表中还是在 FROM 子句中)。
在 Manticore 3 中,kill-list 会在 searchd 启动时加载表或表被轮换时应用。表配置中的新指令 killlist_target 指定目标表,并定义应从源表中用于抑制的文档 ID。这些可以是定义的 kill-list 中的 ID、表的实际文档 ID 或两者。
来自 kill-list 的文档会从目标表中删除,即使搜索不包含提供 kill-list 的表,也不会在结果中返回。因此,搜索表的顺序不再重要。现在,delta, main 和 main, delta 将提供相同的结果。
在以前的版本中,表的轮换遵循配置文件中的顺序。在 Manticore 3 中,表的轮换顺序更智能,并且与 killlist 目标一致。在开始轮换表之前,服务器会根据 killlist_target 定义查找表链。然后,它会先轮换未被任何地方作为 kill-list 目标引用的表。接着,轮换已被已轮换表作为目标的表,依此类推。例如,如果我们执行 indexer --all 并且有 3 个表:main、delta_big(目标为 main)和 delta_small(目标为 delta_big),则首先轮换 delta_small,然后是 delta_big,最后是 main。这样可以确保当依赖表被轮换时,它能获得来自其他表的最新 kill-list。
docinfo- 现在全部为 externinplace_docinfo_gap- 不再需要mva_updates_pool- MVA 不再有专用的更新池,因为现在它们可以直接在 blob 中更新(见下文)。
字符串、JSON 和 MVA 属性可以在 Manticore 3.x 中使用 UPDATE 语句更新。
在 2.x 中,字符串属性需要 REPLACE,JSON 只能更新标量属性(因为它们是定长的),MVA 可以使用 MVA 池更新。现在更新直接在 blob 组件上执行。可能需要调整的一个设置是 attr_update_reserve,它允许更改在 blob 末尾分配的额外空间,用于避免当新值比现有值大时频繁调整大小。
文档 ID 以前是无符号 64 位整数。现在是正有符号 64 位整数。
请阅读关于 RT 模式 的内容。
Manticore 3.x 识别并解析特殊后缀,使得使用带有特殊含义的数值更方便。它们的常见形式是整数 + 字面量,如 10k 或 100d,但不包括 40.3s(因为 40.3 不是整数),也不包括 2d 4h(因为有两个值,而非一个)。字面量不区分大小写,因此 10W 与 10w 相同。目前支持两种类型的后缀:
- 大小后缀 - 可用于定义某些大小(内存缓冲区、磁盘文件、RAM 限制等)参数的字节数。在这些位置的“裸”数字字面意思是字节数(八位字节)。大小值使用后缀
k表示千字节(1k=1024),m表示兆字节(1m=1024k),g表示千兆字节(1g=1024m),t表示太字节(1t=1024g)。 - 时间后缀 - 可用于定义某些时间间隔值,如延迟、超时等。这些参数的“裸”值通常有文档说明的单位,你必须知道数字 100 是表示“100 秒”还是“100 毫秒”。不过,你可以直接写带后缀的值,单位由后缀完全确定。时间值使用后缀
us表示微秒,ms表示毫秒,s表示秒,m表示分钟,h表示小时,d表示天,w表示周。
index_converter 是一个用于将 Sphinx/Manticore Search 2.x 创建的表转换为 Manticore Search 3.x 表格式的工具。该工具可以通过多种方式使用:
$ index_converter --config /home/myuser/manticore.conf --index tablename
$ index_converter --config /home/myuser/manticore.conf --all
$ index_converter --path /var/lib/manticoresearch/data --all
新版本的表默认写入同一文件夹。旧版本的文件会以 .old 扩展名保存。例外的是 .spp(hitlists)文件,这是唯一在新格式中没有任何更改的表组件。
你可以使用 -–output-dir 选项将新表版本保存到不同的文件夹
$ index_converter --config /home/myuser/manticore.conf --all --output-dir /new/path
包含 kill-list 的表是特殊情况。由于 kill-list 的工作方式发生了变化(参见 killlist_target),delta 表应知道应用 kill-list 的目标表。转换表后准备设置应用 kill-list 的目标表有三种方法:
- 转换表时使用
-–killlist-target$ index_converter --config /home/myuser/manticore.conf --index deltaindex --killlist-target mainindex:kl - 在转换前在配置中添加 killlist_target
- 转换后使用 ALTER ... KILLIST_TARGET 命令
以下是 index_converter 选项的完整列表:
--config <file>(简写为-c <file>)告诉 index_converter 使用指定的配置文件。通常,它会在安装目录(例如,如果安装在/usr/local/sphinx,则为/usr/local/manticore/etc/manticore.conf)中查找 manticore.conf,然后是你从 shell 调用 index_converter 时所在的当前目录。--index指定要转换的表--path- 不使用配置文件,而是使用包含表的路径--strip-path- 从表引用的文件名中去除路径:停用词、例外和词形变化--large-docid- 允许转换文档ID大于2^63的文档并显示警告,否则遇到大ID时会直接报错退出。添加此选项是因为在Manticore 3.x中,文档ID是有符号的bigint,而之前是无符号的--output-dir <dir>- 将新文件写入指定文件夹,而不是与现有表文件相同的位置。设置此选项时,现有表文件将保持原位置不变。--all- 转换配置中的所有表--killlist-target <targets>设置将应用kill-list的目标表。此选项应仅与--index选项一起使用
您可以轻松地在各种操作系统上安装和启动 Manticore,包括 Ubuntu、Centos、Debian、Windows 和 MacOS。此外,您还可以将 Manticore 作为 Docker 容器使用。
- Ubuntu
- Debian
- Centos
- Windows
- MacOS
- Docker
wget https://repo.manticoresearch.com/manticore-repo.noarch.deb
sudo dpkg -i manticore-repo.noarch.deb
sudo apt update
sudo apt install manticore manticore-columnar-lib
sudo systemctl start manticorewget https://repo.manticoresearch.com/manticore-repo.noarch.deb
sudo dpkg -i manticore-repo.noarch.deb
sudo apt update
sudo apt install manticore manticore-columnar-lib
sudo systemctl start manticoresudo yum install https://repo.manticoresearch.com/manticore-repo.noarch.rpm
sudo yum install manticore manticore-columnar-lib
sudo systemctl start manticore- 从 https://manticoresearch.com/install/ 下载 Windows 压缩包
- 将压缩包中的所有文件解压到
C:\Manticore - 运行以下命令将 Manticore 安装为服务:
-
C:\Manticore\bin\searchd --install --config C:\Manticore\sphinx.conf.in --servicename Manticore - 从 Microsoft 管理控制台的服务管理单元启动 Manticore。
brew install manticoresearch
brew services start manticoresearchdocker pull manticoresearch/manticore
docker run --name manticore -p9306:9306 -p9308:9308 -p9312:9312 -d manticoresearch/manticore有关持久化数据目录的内容,请阅读如何在生产环境中使用 Manticore docker
默认情况下,Manticore 等待您的连接端口为:
- 端口 9306 用于 MySQL 客户端
- 端口 9308 用于 HTTP/HTTPS 连接
- 端口 9312 用于来自其他 Manticore 节点和基于 Manticore 二进制 API 的客户端的连接
有关 HTTPS 支持的更多详细信息,请参阅我们的学习课程这里。
- SQL
- HTTP
- PHP
- Python
- Python-asyncio
- Javascript
- Java
- C#
- Rust
- Typescript
- Go
mysql -h0 -P9306HTTP 是无状态协议,因此不需要任何特殊的连接阶段。您可以简单地向服务器发送 HTTP 请求并接收响应。要使用 JSON 接口与 Manticore 通信,您可以使用您所选编程语言中的任何 HTTP 客户端库发送 GET 或 POST 请求到服务器并解析 JSON 响应:
curl -s "http://localhost:9308/search"// https://github.com/manticoresoftware/manticoresearch-php
require_once __DIR__ . '/vendor/autoload.php';
$config = ['host'=>'127.0.0.1','port'=>9308];
$client = new \Manticoresearch\Client($config);// https://github.com/manticoresoftware/manticoresearch-python
import manticoresearch
config = manticoresearch.Configuration(
host = "http://127.0.0.1:9308"
)
client = manticoresearch.ApiClient(config)
indexApi = manticoresearch.IndexApi(client)
searchApi = manticoresearch.SearchApi(client)
utilsApi = manticoresearch.UtilsApi(client)// https://github.com/manticoresoftware/manticoresearch-python-asyncio
import manticoresearch
config = manticoresearch.Configuration(
host = "http://127.0.0.1:9308"
)
async with manticoresearch.ApiClient(config) as client:
indexApi = manticoresearch.IndexApi(client)
searchApi = manticoresearch.searchApi(client)
utilsApi = manticoresearch.UtilsApi(client)// https://github.com/manticoresoftware/manticoresearch-javascript
var Manticoresearch = require('manticoresearch');
var client= new Manticoresearch.ApiClient()
client.basePath="http://127.0.0.1:9308";
indexApi = new Manticoresearch.IndexApi(client);
searchApi = new Manticoresearch.SearchApi(client);
utilsApi = new Manticoresearch.UtilsApi(client);// https://github.com/manticoresoftware/manticoresearch-java
import com.manticoresearch.client.*;
import com.manticoresearch.client.model.*;
import com.manticoresearch.client.api.*;
...
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("http://127.0.0.1:9308");
...
IndexApi indexApi = new IndexApi(client);
SearchApi searchApi = new UtilsApi(client);
UtilsApi utilsApi = new UtilsApi(client);// https://github.com/manticoresoftware/manticoresearch-net
using System.Net.Http;
...
using ManticoreSearch.Client;
using ManticoreSearch.Api;
using ManticoreSearch.Model;
...
config = new Configuration();
config.BasePath = "http://localhost:9308";
httpClient = new HttpClient();
httpClientHandler = new HttpClientHandler();
...
var indexApi = new IndexApi(httpClient, config, httpClientHandler);
var searchApi = new SearchApi(httpClient, config, httpClientHandler);
var utilsApi = new UtilsApi(httpClient, config, httpClientHandler);// https://github.com/manticoresoftware/manticoresearch-rust
use std::sync::Arc;
use manticoresearch::{
apis::{
{configuration::Configuration,IndexApi,IndexApiClient,SearchApi,SearchApiClient,UtilsApi,UtilsApiClient}
},
};
async fn maticore_connect {
let configuration = Configuration {
base_path: "http://127.0.0.1:9308".to_owned(),
..Default::default(),
};
let api_config = Arc::new(configuration);
let utils_api = UtilsApiClient::new(api_config.clone());
let index_api = IndexApiClient::new(api_config.clone());
let search_api = SearchApiClient::new(api_config.clone());import {
Configuration,
IndexApi,
SearchApi,
UtilsApi
} from "manticoresearch-ts";
...
const config = new Configuration({
basePath: 'http://localhost:9308',
})
const indexApi = new IndexApi(config);
const searchApi = new SearchApi(config);
const utilsApi = new UtilsApi(config);import (
"context"
manticoreclient "github.com/manticoresoftware/manticoresearch-go"
)
...
configuration := manticoreclient.NewConfiguration()
configuration.Servers[0].URL = "http://localhost:9308"
apiClient := manticoreclient.NewAPIClient(configuration)现在让我们创建一个名为 "products" 的表,包含 2 个字段:
- title - 全文字段,将包含我们产品的标题
- price - 类型为 "float"
请注意,可以省略使用显式创建语句创建表。更多信息请参见自动模式。
有关创建表的不同方式的更多信息,请参阅我们的学习课程:
- SQL
- HTTP
- PHP
- Python
- Python-asyncio
- Javascript
- Java
- C#
- Rust
- TypeScript
- Go
create table products(title text, price float) morphology='stem_en';POST /cli -d "create table products(title text, price float) morphology='stem_en'"$index = new \Manticoresearch\Index($client);
$index->setName('products');
$index->create([
'title'=>['type'=>'text'],
'price'=>['type'=>'float'],
],['morphology' => 'stem_en']);utilsApi.sql('create table products(title text, price float) morphology=\'stem_en\'')await utilsApi.sql('create table products(title text, price float) morphology=\'stem_en\'')res = await utilsApi.sql('create table products(title text, price float) morphology=\'stem_en\'');utilsApi.sql("create table products(title text, price float) morphology='stem_en'", true);utilsApi.Sql("create table products(title text, price float) morphology='stem_en'", true);utils_api.sql("create table products(title text, price float) morphology='stem_en'", Some(true)).await;res = await utilsApi.sql('create table products(title text, price float) morphology=\'stem_en\'');res := apiClient.UtilsAPI.Sql(context.Background()).Body("create table products(title text, price float) morphology='stem_en'").Execute();Query OK, 0 rows affected (0.02 sec){
"total":0,
"error":"",
"warning":""
}- SQL
- JSON
- PHP
- Python
- Python-asyncio
- Javascript
- Java
- C#
- Rust
- TypeScript
- Go
insert into products(title,price) values ('Crossbody Bag with Tassel', 19.85), ('microfiber sheet set', 19.99), ('Pet Hair Remover Glove', 7.99);"id":0 或无 id 会强制自动生成 ID。
POST /insert
{
"table":"products",
"doc":
{
"title" : "Crossbody Bag with Tassel",
"price" : 19.85
}
}
POST /insert
{
"table":"products",
"doc":
{
"title" : "microfiber sheet set",
"price" : 19.99
}
}
POST /insert
{
"table":"products",
"doc":
{
"title" : "Pet Hair Remover Glove",
"price" : 7.99
}
}$index->addDocuments([
['title' => 'Crossbody Bag with Tassel', 'price' => 19.85],
['title' => 'microfiber sheet set', 'price' => 19.99],
['title' => 'Pet Hair Remover Glove', 'price' => 7.99]
]);indexApi.insert({"table" : "products", "doc" : {"title" : "Crossbody Bag with Tassel", "price" : 19.85}})
indexApi.insert({"table" : "products", "doc" : {"title" : "microfiber sheet set", "price" : 19.99}})
indexApi.insert({"table" : "products", "doc" : {"title" : "Pet Hair Remover Glove", "price" : 7.99}})await indexApi.insert({"table" : "products", "doc" : {"title" : "Crossbody Bag with Tassel", "price" : 19.85}})
await indexApi.insert({"table" : "products", "doc" : {"title" : "microfiber sheet set", "price" : 19.99}})
await indexApi.insert({"table" : "products", "doc" : {"title" : "Pet Hair Remover Glove", "price" : 7.99}})res = await indexApi.insert({"table" : "products", "doc" : {"title" : "Crossbody Bag with Tassel", "price" : 19.85}});
res = await indexApi.insert({"table" : "products", "doc" : {"title" : "microfiber sheet set", "price" : 19.99}});
res = await indexApi.insert({"table" : "products", "doc" : {"title" : "Pet Hair Remover Glove", "price" : 7.99}});InsertDocumentRequest newdoc = new InsertDocumentRequest();
HashMap<String,Object> doc = new HashMap<String,Object>(){{
put("title","Crossbody Bag with Tassel");
put("price",19.85);
}};
newdoc.index("products").setDoc(doc);
sqlresult = indexApi.insert(newdoc);
newdoc = new InsertDocumentRequest();
doc = new HashMap<String,Object>(){{
put("title","microfiber sheet set");
put("price",19.99);
}};
newdoc.index("products").setDoc(doc);
sqlresult = indexApi.insert(newdoc);
newdoc = new InsertDocumentRequest();
doc = new HashMap<String,Object>(){{
put("title","Pet Hair Remover Glove");
put("price",7.99);
}};
newdoc.index("products").setDoc(doc);
indexApi.insert(newdoc);Dictionary<string, Object> doc = new Dictionary<string, Object>();
doc.Add("title","Crossbody Bag with Tassel");
doc.Add("price",19.85);
InsertDocumentRequest insertDocumentRequest = new InsertDocumentRequest(index: "products", doc: doc);
sqlresult = indexApi.Insert(insertDocumentRequest);
doc = new Dictionary<string, Object>();
doc.Add("title","microfiber sheet set");
doc.Add("price",19.99);
insertDocumentRequest = new InsertDocumentRequest(index: "products", doc: doc);
sqlresult = indexApi.Insert(insertDocumentRequest);
doc = new Dictionary<string, Object>();
doc.Add("title","Pet Hair Remover Glove");
doc.Add("price",7.99);
insertDocumentRequest = new InsertDocumentRequest(index: "products", doc: doc);
sqlresult = indexApi.Insert(insertDocumentRequest);let mut doc1 = HashMap::new();
doc1.insert("title".to_string(), serde_json::json!("Crossbody Bag with Tassel"));
doc1.insert("price".to_string(), serde_json::json!(19.85));
let insert_req1 = InsertDocumentRequest::new("products".to_string(), serde_json::json!(doc1));
let insert_res1 = index_api.insert(insert_req1).await;
let mut doc2 = HashMap::new();
doc2.insert("title".to_string(), serde_json::json!("microfiber sheet set"));
doc2.insert("price".to_string(), serde_json::json!(19.99));
let insert_req2 = InsertDocumentRequest::new("products".to_string(), serde_json::json!(doc2));
let insert_res2 = index_api.insert(insert_req2).await;
let mut doc3 = HashMap::new();
doc3.insert("title".to_string(), serde_json::json!("Pet Hair Remover Glove"));
doc3.insert("price".to_string(), serde_json::json!(7.99));
let insert_req3 = InsertDocumentRequest::new("products".to_string(), serde_json::json!(doc3));
let insert_res3 = index_api.insert(insert_req3).await;res = await indexApi.insert({
index: 'test',
id: 1,
doc: { content: 'Text 1', name: 'Doc 1', cat: 1 },
});
res = await indexApi.insert({
index: 'test',
id: 2,
doc: { content: 'Text 2', name: 'Doc 2', cat: 2 },
});
res = await indexApi.insert({
index: 'test',
id: 3,
doc: { content: 'Text 3', name: 'Doc 3', cat: 7 },
});indexDoc := map[string]interface{} {"content": "Text 1", "name": "Doc 1", "cat": 1 }
indexReq := manticoreclient.NewInsertDocumentRequest("products", indexDoc)
indexReq.SetId(1)
apiClient.IndexAPI.Insert(context.Background()).InsertDocumentRequest(*indexReq).Execute()
indexDoc = map[string]interface{} {"content": "Text 2", "name": "Doc 3", "cat": 2 }
indexReq = manticoreclient.NewInsertDocumentRequest("products", indexDoc)
indexReq.SetId(2)
apiClient.IndexAPI.Insert(context.Background()).InsertDocumentRequest(*indexReq).Execute()
indexDoc = map[string]interface{} {"content": "Text 3", "name": "Doc 3", "cat": 7 }
indexReq = manticoreclient.NewInsertDocumentRequest("products", indexDoc)
indexReq.SetId(3)
apiClient.IndexAPI.Insert(context.Background()).InsertDocumentRequest(*indexReq).Execute()Query OK, 3 rows affected (0.01 sec){
"table": "products",
"_id": 0,
"created": true,
"result": "created",
"status": 201
}
{
"table": "products",
"_id": 0,
"created": true,
"result": "created",
"status": 201
}
{
"table": "products",
"_id": 0,
"created": true,
"result": "created",
"status": 201
}更多关于该主题的详细信息请参见:
让我们查找其中一份文档。我们将使用的查询是“remove hair”。如您所见,它找到了标题为“Pet Hair Remover Glove”的文档,并且高亮显示了其中的“Hair remover”,即使查询中是“remove”,而不是“remover”。这是因为在创建表时,我们启用了英文词干处理(morphology "stem_en")。
- SQL
- JSON
- PHP
- Python
- Python-asyncio
- javascript
- Java
- C#
- Rust
- TypeScript
- Go
select id, highlight(), price from products where match('remove hair');POST /search
{
"table": "products",
"query": { "match": { "title": "remove hair" } },
"highlight":
{
"fields": ["title"]
}
}$result = $index->search('@title remove hair')->highlight(['title'])->get();
foreach($result as $doc)
{
echo "Doc ID: ".$doc->getId()."\n";
echo "Doc Score: ".$doc->getScore()."\n";
echo "Document fields:\n";
print_r($doc->getData());
echo "Highlights: \n";
print_r($doc->getHighlight());
}searchApi.search({"table":"products","query":{"query_string":"@title remove hair"},"highlight":{"fields":["title"]}})await searchApi.search({"table":"products","query":{"query_string":"@title remove hair"},"highlight":{"fields":["title"]}})res = await searchApi.search({"table":"products","query":{"query_string":"@title remove hair"}"highlight":{"fields":["title"]}});query = new HashMap<String,Object>();
query.put("query_string","@title remove hair");
searchRequest = new SearchRequest();
searchRequest.setIndex("forum");
searchRequest.setQuery(query);
HashMap<String,Object> highlight = new HashMap<String,Object>(){{
put("fields",new String[] {"title"});
}};
searchRequest.setHighlight(highlight);
searchResponse = searchApi.search(searchRequest);object query = new { query_string="@title remove hair" };
var searchRequest = new SearchRequest("products", query);
var highlight = new Highlight();
highlight.Fieldnames = new List<string> {"title"};
searchRequest.Highlight = highlight;
searchResponse = searchApi.Search(searchRequest);let query = SearchQuery {
query_string: Some(serde_json::json!("@title remove hair").into()),
..Default::default()
};
let highlight = Highlight {
fields: Some(serde_json::json!(["title"]).into()),
..Default::default()
};
let search_req = SearchRequest {
table: "products".to_string(),
query: Some(Box::new(query)),
highlight: Some(Box::new(highlight)),
..Default::default(),
};
let search_res = search_api.search(search_req).await;res = await searchApi.search({
index: 'test',
query: { query_string: {'text 1'} },
highlight: {'fields': ['content'] }
});searchRequest := manticoreclient.NewSearchRequest("test")
query := map[string]interface{} {"query_string": "text 1"};
searchRequest.SetQuery(query);
highlightField := manticoreclient.NewHighlightField("content")
fields := []interface{}{ highlightField }
highlight := manticoreclient.NewHighlight()
highlight.SetFields(fields)
searchRequest.SetHighlight(highlight);
res, _, _ := apiClient.SearchAPI.Search(context.Background()).SearchRequest(*searchRequest).Execute()+---------------------+-------------------------------+----------+
| id | highlight() | price |
+---------------------+-------------------------------+----------+
| 1513686608316989452 | Pet <b>Hair Remover</b> Glove | 7.990000 |
+---------------------+-------------------------------+----------+
1 row in set (0.00 sec){
"took": 0,
"timed_out": false,
"hits": {
"total": 1,
"hits": [
{
"_id": 1513686608316989452,
"_score": 1680,
"_source": {
"price": 7.99,
"title": "Pet Hair Remover Glove"
},
"highlight": {
"title": [
"Pet <b>Hair Remover</b> Glove"
]
}
}
]
}
}Doc ID: 1513686608316989452
Doc Score: 1680
Document fields:
Array
(
[price] => 7.99
[title] => Pet Hair Remover Glove
)
Highlights:
Array
(
[title] => Array
(
[0] => Pet <b>Hair Remover</b> Glove
)
)`
{'hits': {'hits': [{u'_id': u'1513686608316989452',
u'_score': 1680,
u'_source': {u'title': u'Pet Hair Remover Glove', u'price':7.99},
u'highlight':{u'title':[u'Pet <b>Hair Remover</b> Glove']}}}],
'total': 1},
'profile': None,
'timed_out': False,
'took': 0}{'hits': {'hits': [{u'_id': u'1513686608316989452',
u'_score': 1680,
u'_source': {u'title': u'Pet Hair Remover Glove', u'price':7.99},
u'highlight':{u'title':[u'Pet <b>Hair Remover</b> Glove']}}}],
'total': 1},
'profile': None,
'timed_out': False,
'took': 0}{"hits": {"hits": [{"_id": 1513686608316989452,
"_score": 1680,
"_source": {"title": "Pet Hair Remover Glove", "price":7.99},
"highlight":{"title":["Pet <b>Hair Remover</b> Glove"]}}],
"total": 1},
"profile": None,
"timed_out": False,
"took": 0}class SearchResponse {
took: 84
timedOut: false
hits: class SearchResponseHits {
total: 1
maxScore: null
hits: [{_id=1513686608316989452, _score=1, _source={price=7.99, title=Pet Hair Remover Glove}, highlight={title=[Pet <b>Hair Remover</b> Glove]}}]
aggregations: null
}
profile: null
}class SearchResponse {
took: 103
timedOut: false
hits: class SearchResponseHits {
total: 1
maxScore: null
hits: [{_id=1513686608316989452, _score=1, _source={price=7.99, title=Pet Hair Remover Glove}, highlight={title=[Pet <b>Hair Remover</b> Glove]}}]
aggregations: null
}
profile: null
}class SearchResponse {
took: 103
timedOut: false
hits: class SearchResponseHits {
total: 1
maxScore: null
hits: [{_id=1513686608316989452, _score=1, _source={price=7.99, title=Pet Hair Remover Glove}, highlight={title=[Pet <b>Hair Remover</b> Glove]}}]
aggregations: null
}
profile: null
}{
"hits":
{
"hits":
[{
"_id": 1,
"_score": 1400,
"_source": {"content":"Text 1","name":"Doc 1","cat":1},
"highlight": {"content":["<b>Text 1</b>"]}
}],
"total": 1
},
"profile": None,
"timed_out": False,
"took": 0
}{
"hits":
{
"hits":
[{
"_id": 1,
"_score": 1400,
"_source": {"content":"Text 1","name":"Doc 1","cat":1},
"highlight": {"content":["<b>Text 1</b>"]}
}],
"total": 1
},
"profile": None,
"timed_out": False,
"took": 0
}关于 Manticore 中可用的不同搜索选项的更多信息,请参见我们的学习课程:
- SQL
- JSON
- PHP
- Python
- Python-asyncio
- javascript
- Java
- C#
- Rust
- TypeScript
- Go
update products set price=18.5 where id = 1513686608316989452;POST /update
{
"table": "products",
"id": 1513686608316989452,
"doc":
{
"price": 18.5
}
}$doc = [
'body' => [
'table' => 'products',
'id' => 2,
'doc' => [
'price' => 18.5
]
]
];
$response = $client->update($doc);indexApi = api = manticoresearch.IndexApi(client)
indexApi.update({"table" : "products", "id" : 1513686608316989452, "doc" : {"price":18.5}})indexApi = api = manticoresearch.IndexApi(client)
await indexApi.update({"table" : "products", "id" : 1513686608316989452, "doc" : {"price":18.5}})res = await indexApi.update({"table" : "products", "id" : 1513686608316989452, "doc" : {"price":18.5}});UpdateDocumentRequest updateRequest = new UpdateDocumentRequest();
doc = new HashMap<String,Object >(){{
put("price",18.5);
}};
updateRequest.index("products").id(1513686608316989452L).setDoc(doc);
indexApi.update(updateRequest);Dictionary<string, Object> doc = new Dictionary<string, Object>();
doc.Add("price", 18.5);
UpdateDocumentRequest updateDocumentRequest = new UpdateDocumentRequest(index: "products", id: 1513686608316989452L, doc: doc);
indexApi.Update(updateDocumentRequest);let mut doc = HashMap::new();
doc.insert("price".to_string(), serde_json::json!(18.5));
let update_req = UpdateDocumentRequest {
table: serde_json::json!("products"),
doc: serde_json::json!(doc),
id: serde_json::json!(1513686608316989452),
..Default::default(),
};
let update_res = index_api.update(update_req).await;res = await indexApi.update({ index: "test", id: 1, doc: { cat: 10 } });updDoc = map[string]interface{} {"cat": 10}
updRequest = manticoreclient.NewUpdateDocumentRequest("test", updDoc)
updRequest.SetId(1)
res, _, _ = apiClient.IndexAPI.Update(context.Background()).UpdateDocumentRequest(*updRequest).Execute()Query OK, 1 row affected (0.00 sec){
"table": "products",
"_id": 1513686608316989452,
"result": "updated"
}- SQL
- JSON
- PHP
- Python
- Python-asyncio
- javascript
- Java
- C#
- Rust
- TypeScript
- Go
delete from products where price < 10;POST /delete
{
"table": "products",
"query":
{
"range":
{
"price":
{
"lte": 10
}
}
}
}$result = $index->deleteDocuments(new \Manticoresearch\Query\Range('price',['lte'=>10]));indexApi.delete({"table" : "products", "query": {"range":{"price":{"lte":10}}}})await indexApi.delete({"table" : "products", "query": {"range":{"price":{"lte":10}}}})res = await indexApi.delete({"table" : "products", "query": {"range":{"price":{"lte":10}}}});DeleteDocumentRequest deleteRequest = new DeleteDocumentRequest();
query = new HashMap<String,Object>();
query.put("range",new HashMap<String,Object>(){{
put("price",new HashMap<String,Object>(){{
put("lte",10);
}});
}});
deleteRequest.index("products").setQuery(query);
indexApi.delete(deleteRequest);Dictionary<string, Object> price = new Dictionary<string, Object>();
price.Add("lte", 10);
Dictionary<string, Object> range = new Dictionary<string, Object>();
range.Add("price", price);
DeleteDocumentRequest deleteDocumentRequest = new DeleteDocumentRequest(index: "products", query: range);
indexApi.Delete(deleteDocumentRequest);let mut price_range= HashMap::new();
price_range.insert("lte".to_string(), serde_json::json!(10));
let mut range= HashMap::new();
range.insert("price".to_string(), serde_json::json!(price_range));
let delete_req = DeleteDocumentRequest {
table: "products".to_string(),
query: serde_json::json!(range),
..Default::default(),
};
index_api.delete(delete_req).await;res = await indexApi.delete({
index: 'test',
query: { match: { '*': 'Text 1' } },
});delRequest := manticoreclient.NewDeleteDocumentRequest("test")
matchExpr := map[string]interface{} {"*": "Text 1t"}
delQuery := map[string]interface{} {"match": matchExpr }
delRequest.SetQuery(delQuery)
res, _, _ := apiClient.IndexAPI.Delete(context.Background()).DeleteDocumentRequest(*delRequest).Execute();Query OK, 1 row affected (0.00 sec){
"table": "products",
"deleted": 1
}Array
(
[_index] => products
[deleted] => 1
)安装后,Manticore Search 服务不会自动启动。要启动 Manticore,请运行以下命令:
sudo systemctl start manticore
要停止 Manticore,请运行以下命令:
sudo systemctl stop manticore
Manticore 服务设置为开机启动。您可以通过运行以下命令检查:
sudo systemctl is-enabled manticore
如果您想禁用 Manticore 开机启动,请运行:
sudo systemctl disable manticore
要使 Manticore 开机启动,请运行:
sudo systemctl enable manticore
searchd 进程会将启动信息记录在 systemd 日志中。如果启用了 systemd 日志记录,您可以使用以下命令查看记录的信息:
sudo journalctl -u manticore
systemctl set-environment _ADDITIONAL_SEARCHD_PARAMS 允许您指定 Manticore Search 守护进程启动时应使用的自定义启动参数。完整列表请参见这里。
例如,要以调试日志级别启动 Manticore,您可以运行:
systemctl set-environment _ADDITIONAL_SEARCHD_PARAMS='--logdebug'
systemctl restart manticore
要撤销该操作,运行:
systemctl set-environment _ADDITIONAL_SEARCHD_PARAMS=''
systemctl restart manticore
注意,systemd 环境变量在服务器重启时会被重置。
可以使用 service 命令启动和停止 Manticore:
sudo service manticore start
sudo service manticore stop
在 RedHat 系统上启用 sysV 服务开机启动,请运行:
chkconfig manticore on
在 Debian 系统(包括 Ubuntu)上启用 sysV 服务开机启动,请运行:
update-rc.d manticore defaults
请注意,searchd 由 init 系统以 manticore 用户身份启动,服务器创建的所有文件都将归该用户所有。如果 searchd 以例如 root 用户身份启动,文件权限将被更改,这可能导致再次以服务方式运行 searchd 时出现问题。