从源码编译 Manticore Search 可以实现自定义的构建配置,例如禁用某些功能或添加新的补丁进行测试。例如,您可能希望从源码编译并禁用嵌入式 ICU,以便使用系统上安装的、可以独立于 Manticore 升级的不同版本。如果您有兴趣为 Manticore Search 项目做贡献,这也很有用。
为了准备官方发布和开发包,我们使用 Docker 和一个特殊的构建镜像。该镜像包含必要的工具,并设计为与外部系统根目录(sysroots)一起使用,因此一个容器可以为所有操作系统构建软件包。您可以使用 Dockerfile 和 README 来构建该镜像,或者使用 Docker Hub 上的镜像。这是为任何支持的操作系统和架构创建二进制文件的最简单方法。运行容器时,您还需要指定以下环境变量:
DISTR:目标平台:bionic、focal、jammy、buster、bullseye、bookworm、rhel7、rhel8、rhel9、rhel10、macos、windows、freebsd13arch:架构:x86_64、x64(适用于 Windows)、aarch64、arm64(适用于 Macos)SYSROOT_URL:系统根目录归档文件的 URL。除非您自己构建系统根目录(说明可以在这里找到),否则可以使用 https://repo.manticoresearch.com/repository/sysroots。- 参考 CI 工作流文件以查找您可能需要使用的其他环境变量:
要查找 DISTR 和 arch 的可能值,您可以参考目录 https://repo.manticoresearch.com/repository/sysroots/roots_with_zstd/,因为它包含了所有支持组合的系统根目录。
之后,在 Docker 容器内构建软件包就像调用以下命令一样简单:
cmake -DPACK=1 /path/to/sources
cmake --build .
例如,要创建一个类似于 Manticore 核心团队提供的官方版本的 Ubuntu Jammy 软件包,您应该在包含 Manticore Search 源代码的目录中执行以下命令。该目录是从 https://github.com/manticoresoftware/manticoresearch 克隆的仓库的根目录:
docker run -it --rm \
-e CACHEB="../cache" \
-e DIAGNOSTIC=1 \
-e PACK_ICUDATA=0 \
-e NO_TESTS=1 \
-e DISTR=jammy \
-e boost=boost_nov22 \
-e sysroot=roots_nov22 \
-e arch=x86_64 \
-e CTEST_CMAKE_GENERATOR=Ninja \
-e CTEST_CONFIGURATION_TYPE=RelWithDebInfo \
-e WITH_COVERAGE=0 \
-e SYSROOT_URL="https://repo.manticoresearch.com/repository/sysroots" \
-e HOMEBREW_PREFIX="" \
-e PACK_GALERA=0 \
-e UNITY_BUILD=1 \
-v $(pwd):/manticore_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
manticoresearch/external_toolchain:vcpkg331_20250114 bash
# following is to be run inside docker shell
cd /manticore_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/
mkdir build && cd build
cmake -DPACK=1 ..
export CMAKE_TOOLCHAIN_FILE=$(pwd)/dist/build_dockers/cross/linux.cmake
cmake --build .
# or if you want to build packages:
# cmake --build . --target package
在某些情况下(例如 Centos),需要较长的源代码目录路径,否则可能无法成功构建源代码。
同样地,您不仅可以为流行的 Linux 发行版构建二进制文件或软件包,还可以为 FreeBSD、Windows 和 macOS 构建。
您也可以使用相同的特殊 Docker 镜像来构建 SRPM:
docker run -it --rm \
-e CACHEB="../cache" \
-e DIAGNOSTIC=1 \
-e PACK_ICUDATA=0 \
-e NO_TESTS=1 \
-e DISTR=rhel8 \
-e boost=boost_rhel_feb17 \
-e sysroot=roots_nov22 \
-e arch=x86_64 \
-e CTEST_CMAKE_GENERATOR=Ninja \
-e CTEST_CONFIGURATION_TYPE=RelWithDebInfo \
-e WITH_COVERAGE=0 \
-e SYSROOT_URL="https://repo.manticoresearch.com/repository/sysroots" \
-e HOMEBREW_PREFIX="" \
-e PACK_GALERA=0 \
-e UNITY_BUILD=1 \
-v $(pwd):/manticore_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
manticoresearch/external_toolchain:vcpkg331_20250114 bash
# following is to be run inside docker shell
cd /manticore_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/
mkdir build && cd build
cmake -DPACK=1 ..
export CMAKE_TOOLCHAIN_FILE=$(pwd)/../dist/build_dockers/cross/linux.cmake
# The CPackSourceConfig.cmake file is now generated in the build directory
cpack -G RPM --config ./CPackSourceConfig.cmake
这将生成一个包含所有源代码的源 RPM(.src.rpm 文件)。
生成 SRPM 后,您可以使用它来构建完整的二进制 RPM 软件包集:
# Install build tools and dependencies
dnf install -y rpm-build cmake gcc-c++ boost-devel epel-release
# Install SRPM dependencies automatically
dnf builddep -y manticore-*.src.rpm
# Build all binary RPMs from the SRPM
rpmbuild --rebuild manticore-*.src.rpm
# Find the generated packages
ls ~/rpmbuild/RPMS/*/manticore*
注意:要从 SRPM 构建 RPM,您需要确保 SRPM 中列出的所有依赖项都已完全安装,这可能具有挑战性。 SRPM 在以下方面仍然有用:
- 审计构建过程或检查源代码和 spec 文件
- 对构建进行自定义修改或打补丁
- 了解二进制文件是如何生成的
- 满足开源许可证合规性要求
不使用构建 Docker 来编译 Manticore 不推荐,但如果您需要这样做,以下是一些您可能需要了解的信息:
- C++ 编译器
- 在 Linux 中 - 可以使用 GNU(4.7.2 及以上版本)或 Clang
- 在 Windows 中 - Microsoft Visual Studio 2019 及以上版本(社区版即可)
- 在 macOS 中 - Clang(来自 XCode 的命令行工具,使用
xcode-select --install安装)。
- Bison, Flex - 在大多数系统上,它们可以作为软件包使用;在 Windows 上,它们在 cygwin 框架中可用。
- Cmake - 在所有平台上使用(需要 3.19 或更高版本)
Manticore 源代码托管在 GitHub 上。
要获取源代码,请克隆仓库,然后检出所需的分支或标签。分支 master 代表主要的开发分支。发布时,会创建一个版本标签,例如 3.6.0,并为当前版本启动一个新分支,在本例中为 manticore-3.6.0。该版本分支在所有更改后的头部被用作构建所有二进制发布的源代码。例如,要获取 3.6.0 版本的源代码,您可以运行:
git clone https://github.com/manticoresoftware/manticoresearch.git
cd manticoresearch
git checkout manticore-3.6.0
您可以通过使用 "Download ZIP" 按钮从 GitHub 下载所需的代码。.zip 和 .tar.gz 格式都适用。
wget -c https://github.com/manticoresoftware/manticoresearch/archive/refs/tags/3.6.0.tar.gz
tar -zxf 3.6.0.tar.gz
cd manticoresearch-3.6.0
Manticore 使用 CMake。假设您在克隆的仓库的根目录内:
mkdir build && cd build
cmake ..
CMake 将检查可用的功能并根据它们配置构建。默认情况下,如果可用,所有功能都被视为启用。该脚本还会下载并构建一些外部库,假设您想使用它们。隐式地,您将获得最大数量功能的支持。
您也可以通过标志和选项显式地配置构建。要启用功能 FOO,请在 CMake 调用中添加 -DFOO=1。
要禁用它,请使用 -DFOO=0。如果没有明确说明,启用一个不可用的功能(例如,在 MS Windows 构建中 WITH_GALERA)会导致配置失败并出现错误。禁用一个功能不仅会从构建中排除该功能,还会禁用对该系统的检查,并禁用任何相关外部库的下载/构建。
- USE_SYSLOG - 允许在 query logging 中使用
syslog。 - WITH_GALERA -启用对搜索守护进程复制的支持。将在构建时配置此支持,并下载、构建并包含 Galera 库的源代码到发行/安装包中。通常,使用 Galera 构建是安全的,但不分发库本身(即没有 Galera 模块,没有复制)。然而,有时您可能需要显式地禁用它,例如如果您想构建一个设计上无法加载任何库的静态二进制文件,以便即使守护进程内部存在对 'dlopen' 函数的调用也会导致链接错误。
- WITH_RE2 - 使用 RE2 正则表达式库构建。这对于 REGEX() 等函数以及 regexp_filter
功能。 - WITH_RE2_FORCE_STATIC - 下载 RE2 的源代码,编译并静态链接,以便最终二进制文件不依赖系统中共享的
RE2库。 - WITH_STEMMER - 使用 Snowball 词干提取库构建。
- WITH_STEMMER_FORCE_STATIC - 下载 Snowball 的源代码,编译并静态链接,以便最终二进制文件不依赖系统中共享的
libstemmer库。 - WITH_ICU - 使用 ICU (International Components for Unicode) 库构建。它用于对中文文本进行分词。当设置 morphology=
icu_chinese时会使用它。 - WITH_JIEBA - 使用 Jieba 中文分词工具构建。它用于对中文文本进行分词。当设置 morphology=
jieba_chinese时会使用它。 - WITH_ICU_FORCE_STATIC - 下载 ICU 的源代码,编译并静态链接,以便最终二进制文件不依赖系统中共享的
icu库。还会将 ICU 数据文件包含到安装/发行包中。静态链接的 ICU 的目的是使用已知版本的库,以确保行为确定且不依赖任何系统库。您更可能希望使用系统 ICU,因为它可以随着时间更新而无需重新编译 Manticore 守护进程。在这种情况下,您需要显式禁用此选项。这样还可以节省 ICU 数据文件占用的空间(约 30M),因为它不会包含在发行包中。 - WITH_SSL - 用于支持 HTTPS 以及与守护进程的加密 MySQL 连接。系统的 OpenSSL 库将链接到守护进程。这意味着启动守护进程时需要 OpenSSL。对于支持 HTTPS,这是强制性的,但对于服务器本身并非严格必要(即没有 SSL 则无法通过 HTTPS 连接,但其他协议仍可工作)。Manticore 可以使用从 1.0.2 到 1.1.1 的 SSL 库版本, 但请注意 出于安全考虑,强烈建议使用最新的 SSL
库。目前仅支持 v1.1.1,其余版本已过时(
参见 openssl 发布策略 - WITH_ZLIB - 索引器用于处理来自 MySQL 的压缩列。守护进程用于提供对压缩 MySQL 协议的支持。
- WITH_ODBC - 索引器用于支持来自 ODBC 提供者的索引源(它们通常是 UnixODBC 和 iODBC)。在 MS Windows 上,ODBC 是处理 MS SQL 源的正确方法,因此对
MSSQL的索引也意味着启用此标志。 - DL_ODBC - 不与 ODBC 库链接。如果 ODBC 已链接但不可用,则即使您想处理与 ODBC 无关的内容,也无法启动 indexer 工具。此选项要求索引器仅在处理 ODBC 源时才在运行时加载该库。
- ODBC_LIB - ODBC 库文件的名称。当您想处理 ODBC 源时,索引器将尝试加载该文件。此选项根据可用的 ODBC 共享库检测自动写入。您也可以在运行索引器之前,通过设置环境变量
ODBC_LIB并指定备用库的正确路径来覆盖该名称。 - WITH_EXPAT - 索引器用于支持对 xmlpipe 源的索引。
- DL_EXPAT - 不与 EXPAT 库链接。如果 EXPAT 已链接但不可用,则即使您想处理与 xmlpipe 无关的内容,也无法启动
indexer工具。此选项要求索引器仅在处理 xmlpipe 源时才在运行时加载该库。 - EXPAT_LIB - EXPAT 库文件的名称。当您想处理 xmlpipe 源时,索引器将尝试加载该文件。此选项根据可用的 EXPAT 共享库检测自动写入。您也可以在运行索引器之前,通过设置环境变量
EXPAT_LIB并指定备用库的正确路径来覆盖该名称。 - WITH_ICONV - 在使用索引器索引 xmlpipe 源时,用于支持不同的编码。
- DL_ICONV - 不与 iconv 库链接。如果 iconv 已链接但不可用,则即使您想处理与 xmlpipe 无关的内容,也无法启动
indexer工具。此选项要求索引器仅在处理 xmlpipe 源时才在运行时加载该库。 - ICONV_LIB - iconv 库文件的名称。当您想处理 xmlpipe 源时,索引器将尝试加载该文件。此选项根据可用的 iconv 共享库检测自动写入。您也可以在运行索引器之前,通过设置环境变量
ICONV_LIB并指定备用库的正确路径来覆盖该名称。 - WITH_MYSQL - 索引器用于支持索引 MySQL 源。
- DL_MYSQL - 不与 MySQL 库链接。如果 MySQL 已链接但不可用,则即使您想处理与 MySQL 无关的内容,也无法启动 the
indexer工具。此选项要求索引器仅在处理 MySQL 源时才在运行时加载该库。 - MYSQL_LIB -- MySQL 库文件的名称。当您想处理 MySQL 源时,索引器将尝试加载该文件。此选项根据可用的 MySQL 共享库检测自动写入。您也可以在运行索引器之前,通过设置环境变量
MYSQL_LIB并指定备用库的正确路径来覆盖该名称。 - WITH_POSTGRESQL - 索引器用于支持索引 PostgreSQL 源。
- DL_POSTGRESQL - 不与 PostgreSQL 库链接。如果 PostgreSQL 已链接但不可用,则即使您想处理与 PostgreSQL 无关的内容,也无法启动
indexerool。此选项要求索引器仅在处理 PostgreSQL 源时才在运行时加载该库。 - POSTGRESQL_LIB - PostgreSQL 库文件的名称。索引器在处理 PostgreSQL 源时将尝试加载指定的 PostgreSQL 库文件。此选项根据可用的 PostgreSQL 共享库检测自动确定。您也可以在运行索引器之前,通过提供环境变量
POSTGRESQL_LIB并指定备用库的正确路径来覆盖该名称。 - LOCALDATADIR - 守护进程存储 binlogs 的默认路径。如果此路径未在守护进程的运行时配置中提供或被显式禁用(即与此构建配置无关的
manticore.conf文件),则 binlogs 将放置在此路径。它通常是绝对路径,但也可以使用相对路径。您通常无需更改此配置定义的默认值,根据目标系统,可能类似/var/data、/var/lib/manticore/data或/usr/local/var/lib/manticore/data。 - FULL_SHARE_DIR - 存储所有资源的默认路径。在启动任何使用该文件夹中文件的工具之前,可以通过环境变量
FULL_SHARE_DIR覆盖此路径。这是一个重要路径,因为许多内容默认都期望在此处找到,包括预定义字符集表、停用词、manticore 模块和 icu 数据文件,均放置于该文件夹中。配置脚本通常会将此路径确定为类似/usr/share/manticore或/usr/local/share/manticore。 - DISTR_BUILD - 发布软件包选项的快捷方式。它是一个字符串值,表示目标平台的名称。可以用它来代替手动配置所有选项。在 Debian 和 Redhat Linux 上,默认值可能通过轻量级检测确定并设置为通用的 'Debian' 或 'RHEL'。否则,该值未定义。
- PACK - 更方便的快捷方式。它读取环境变量
DISTR,将其赋值给 DISTR_BUILD 参数,然后按常规方式工作。这在使用预先准备的构建系统(如 Docker 容器)中构建时非常有用,DISTR变量在系统级别设置,并反映容器所针对的目标系统。 - CMAKE_INSTALL_PREFIX (path) - Manticore 预期安装的位置。构建不会执行任何安装,但会准备在运行
cmake --install命令或创建包然后安装时执行的安装规则。前缀可以随时更改,即使在安装过程中,也可以通过调用
cmake --install . --prefix /path/to/installation。但是,在配置时,此变量用于初始化LOCALDATADIR和FULL_SHARE_DIR的默认值。例如,在配置时将其设置为/my/custom会
强制将LOCALDATADIR硬编码为/my/custom/var/lib/manticore/data,并将FULL_SHARE_DIR硬编码为
/my/custom/usr/share/manticore。 - BUILD_TESTING (bool) 是否支持测试。如果启用,则在构建后可以运行 'ctest' 来测试构建。请注意,测试需要额外的依赖,例如至少需要 PHP cli、Python 以及可用的 MySQL 服务器和测试数据库。默认情况下,此参数为开启。因此,如果仅想构建,您可能需要通过显式指定 'off' 值来禁用此选项。
- BUILD_SRPMS (bool) 是否显示构建 Source RPM (SRPM) 的说明。由于 CPack 在基于组件的打包方面的限制,SRPM 无法与二进制 RPM 同时生成。启用时,构建系统将显示使用源配置方法正确生成 SRPM 的说明。默认情况下,此参数为关闭。
- LIBS_BUNDLE - 存放各种库的文件夹路径。这主要与 Windows 构建相关,但如果您需要频繁构建以避免每次都下载第三方源代码,也可能很有帮助。默认情况下,配置脚本不会修改此路径;您应手动将所有内容放在其中。例如,当我们需要支持词干提取器时,会从 Snowball 主页下载源代码包,然后解压、配置、构建等。相反,您可以将原始源代码 tarball(即
libstemmer_c.tgz)存放在此文件夹中。下次从头开始构建时,配置脚本将首先在 bundle 中查找,如果在那里找到词干提取器,就不会再次从 Internet 下载。 - CACHEB - 存放第三方库构建结果的文件夹路径。通常,在使用 galera、re2、icu 等功能时,会先从 bundle 下载或获取源代码,然后解压、构建并安装到一个临时内部文件夹。当构建 manticore 时,该文件夹将作为所需功能的依赖所在位置。最后,它们要么与 manticore 链接(如果是库);要么直接进入发行/安装包(如 galera 或 icu 数据)。当 CACHEB 被定义为 cmake 配置参数或系统环境变量时,它将被用作这些构建的目标文件夹。此文件夹可以在多次构建之间保留,这样存储在其中的库就不需要再次构建,从而大大缩短了整个构建过程。
注意,有些选项是以三元组的形式组织的:WITH_XXX,DL_XXX 和 XXX_LIB - 比如 MySQL、ODBC 等的支持。WITH_XXX 决定了接下来两个选项是否有作用。也就是说,如果你将 WITH_ODBC 设置为 0,那么就没有必要提供 DL_ODBC 和 ODBC_LIB,如果整个功能被禁用,这两个选项也不会起作用。同样,如果没有 DL_XXX 选项,XXX_LIB 也没有意义,因为如果不使用动态加载,提供的 XXX_LIB 名称就无用武之地。这默认使用了内部反查。
另外,使用 iconv 库假设了 expat 的存在,并且在 expat 被禁用时是无用的。
另外,一些库可能总是可用的,因此避免与它们链接是没有意义的。例如,在 Windows 中是 ODBC,在 macOS 中是 Expat、iconv 及其他一些库。默认的内部反查会确定这些库,并仅发出 WITH_XXX 而不是 DL_XXX 和 XXX_LIB,这样可以使事情更简单。
对于某些选项,配置文件可能会看起来像这样:
mkdir build && cd build
cmake -DWITH_MYSQL=1 -DWITH_RE2=1 ..
除了通用配置值外,你还可以检查 CMakeCache.txt 文件,该文件会在你运行配置后留在构建文件夹中。任何在那里定义的值都可以在运行 cmake 时显式地重新定义。例如,你可以运行 cmake -DHAVE_GETADDRINFO_A=FALSE ...,这样配置运行不会假设该变量的已调查值,而是使用你提供的值。
环境变量用于提供一些全局设置,这些设置存储在构建配置之外,并始终存在。为了持久化,可以在系统中以不同的方式设置它们 - 例如,将其添加到 .bashrc 文件中,或嵌入到 Dockerfile 中(如果你生成基于 Docker 的构建系统),或在 Windows 的系统偏好设置环境中编写它们。你也可以使用 export VAR=value 在 shell 中临时设置它们。甚至更短,通过在 cmake 调用前预置值,如 CACHEB=/my/cache cmake ... - 这样它只会在这次调用中工作,并不会在下次调用中可见。
一些这样的变量通常由 cmake 和其他工具使用,例如 CXX,它确定当前使用的 C++ 编译器,或者 CXX_FLAGS 提供编译器标志等。
然而,我们有一些特定于 Manticore 配置的变量,这些变量仅为我们的构建而发明。
- CACHEB - 同配置中的 CACHEB 选项
- LIBS_BUNDLE - 同配置中的 LIBS_BUNDLE 选项
- DISTR - 当使用
-DPACK=1时,用于初始化DISTR_BUILD选项。 - DIAGNOSTIC - 使 cmake 配置输出更加详细,解释所有发生的事情
- WRITEB - 假设 LIBS_BUNDLE 并且如果设置了它,将会下载不同工具的源代码文件到 LIBS_BUNDLE 文件夹中。也就是说,如果新的词干版本发布出来 - 你可以手动从捆绑包中删除 libstemmer_c.tgz,然后运行一次性的
WRITEB=1 cmake ...- 它将不会在捆绑包中找到词干的源代码,然后会从供应商站点下载它们到捆绑包中(不使用 WRITEB 时,它们会被下载到构建文件夹内的一个临时文件夹中,并在你清除构建文件夹时消失)。
配置结束时,你可能会看到将要使用的一系列内容:
-- Enabled features compiled in:
* Galera, replication of tables
* re2, a regular expression library
* stemmer, stemming library (Snowball)
* icu, International Components for Unicode
* OpenSSL, for encrypted networking
* ZLIB, for compressed data and networking
* ODBC, for indexing MSSQL (windows) and generic ODBC sources with indexer
* EXPAT, for indexing xmlpipe sources with indexer
* Iconv, for support of different encodings when indexing xmlpipe sources with indexer
* MySQL, for indexing MySQL sources with indexer
* PostgreSQL, for indexing PostgreSQL sources with indexer
cmake --build . --config RelWithDebInfo
要安装,请运行:
cmake --install . --config RelWithDebInfo
要安装到自定义(非默认)文件夹,请运行
cmake --install . --prefix path/to/build --config RelWithDebInfo
要构建包,请使用目标 package。它将根据 -DDISTR_BUILD 选项提供的选择来构建包。默认情况下,它将是一个包含所有二进制文件和辅助文件的简单的 .zip 或 .tgz 存档。
cmake --build . --target package --config RelWithDebInfo
如果你没有更改源路径和构建路径,只需移动到你的构建文件夹并运行:
cmake .
cmake --build . --clean-first --config RelWithDebInfo
如果由于某种原因不起作用,可以删除构建文件夹中的 CMakeCache.txt 文件。在此步骤之后,你需要再次运行 cmake,指向源文件夹并配置选项。
如果这也不起作用,只需清除你的构建文件夹并从头开始。
简而言之 - 就是使用上面写的 --config RelWithDebInfo。它不会出错。
我们使用两种构建类型。开发时使用 Debug - 它以非常有利于开发的方式分配编译器标志和其他内容,意味着调试运行时可以逐行执行。但是,生成的二进制文件对于生产来说既大又慢。
发布时,我们使用另一种类型 - RelWithDebInfo - 这意味着“带有调试信息的发布构建”。它生成带有嵌入调试信息的生产二进制文件。后者随后会被拆分成单独的调试信息包,并与发布的包一起存储,以便在出现问题如崩溃时进行调查和修复。Cmake 还提供了 Release 和 MinSizeRel,但我们不使用它们。如果构建类型不可用,cmake 将创建一个 noconfig 构建。
有两种类型的生成器:单配置和多配置。
- 单配置需要在配置期间提供的构建类型,通过
CMAKE_BUILD_TYPE参数。如果没有定义,则构建将回退到RelWithDebInfo类型,适合你只是从源代码构建 Manticore 而不参与开发。对于显式构建,你应该提供一个构建类型,如-DCMAKE_BUILD_TYPE=Debug。 - 多配置在构建期间选择构建类型。它应该通过
--config选项提供,否则将构建一种称为noconfig的类型,这是不希望的。所以,你应该始终指定构建类型,如--config Debug。
如果您希望指定构建类型但不关心它是 '单' 配置还是 '多' 配置生成器——只需在两个地方都提供必要的键。即,配置时使用 -DCMAKE_BUILD_TYPE=Debug,然后构建时使用 --config Debug。只需确保这两个值相同。如果目标构建器是单配置的,它会使用配置参数。如果是多配置的,配置参数会被忽略,但正确的构建配置会被 --config 键选择。
如果您想要 RelWithDebInfo(即仅构建用于生产)并且知道您在一个单配置平台(即除了 Windows 之外的所有平台)——您可以在在 cmake 调用中省略 --config 标志。那么默认 CMAKE_BUILD_TYPE=RelWithDebInfo 会被配置并使用。所有 '构建'、'安装' 和 '构建包' 命令会变得更短。
Cmake 是工具本身不执行构建,但它生本地构建系统的规则。
通常,它很好地确定可用构建系统,但有时您可能需要明确提供生成器。您
可以运行 cmake -G 并查看可用生成器列表。
- 在 Windows,如果您有多个 Visual Studio 版本安装,您可能需要指定使用哪一个,
如:
cmake -G "Visual Studio 16 2019" .... - 在所有其他平台——通常使用 Unix Makefiles,但您可以指定另一个,如 Ninja,或 Ninja 多配置,如:
多配置`,如:
cmake -GNinja ...或
cmake -G"Ninja Multi-Config" ...Ninja 多配置相当有用,因为它真的 '多配置' 并可用在 Linux/macOS/BSD。用此生成器,您可能将选择配置类型到构建时间,并且您可能在同一构建文件夹构建多个配置,仅改变
--config参数。
- 如果您最终想构建全功能 RPM 包,构建目录路径必须足够长以便正确构建调试符号。
如
/manticore012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789,例如。这是因为 RPM 工具在构建调试信息时会修改编译二进制路径,并且它可能仅覆盖现有空间不会分配更多。前述长路径有 100 字符,足够为此情况。
如果您想使用它们,某些库应该可用。
- 对于索引(
indexer工具):expat,iconv,mysql,odbc,postgresql。没有它们,您仅能处理tsv和csv源。 - 对于服务查询(
searchd守护):可能需要openssl。 - 对于所有(必需,强制!)我们需要 Boost 库。最低版本是 1.61.0,然而,我们构建二进制用较新版本 1.75.0。更近期版本(如 1.76)也应也正常。在 Windows,您可从他们的网站(boost.org)下载预构建 Boost 并安装到默认建议路径(即
C:\\boost...)。在 MacOs,brew 提供的版本正常。在 Linux,您可检查官方仓库可用版本,如果不匹配要求,您可从源码构建。我们需要组件 'context',您也可构建组件 'system' 和 'program_options',它们会必要如果您也想从源码构建 Galera 库。查看dist/build_dockers/xxx/boost_175/Dockerfile为简短自文档脚本/指令如何做。
在构建系统,您需要这些包安装的 'dev' 或 'devel' 版本(即 - libmysqlclient-devel,unixodbc-devel,等。查看我们 dockerfile 为具体包名称)。
在运行系统,这些包应至少存在最终(非 dev)变。(devel 变通常更大,因为它们包含不仅目标二进制,而且不同开发东西如包含头,等)。
除了必要前提,您可能需要预构建 expat,iconv,mysql,和 postgresql 客户端库。您必须要么自己构建它们要么联系我们获取我们构建包(简单 zip 归档,其中这些目标文件夹位于)。
- ODBC 不必要,因为它系统库。
- OpenSSL 可从源码构建或从 https://slproweb.com/products/Win32OpenSSL.html 下载预构建(如 cmake 内部脚本 FindOpenSSL 提及)。
- Boost 可从 https://www.boost.org/ 发布下载预构建。
运行 indexer -h。它会显示哪些功能配置并构建(无论它们明确或探测,不重要):
Built on Linux x86_64 by GNU 8.3.1 compiler.
Configured with these definitions: -DDISTR_BUILD=rhel8 -DUSE_SYSLOG=1 -DWITH_GALERA=1 -DWITH_RE2=1 -DWITH_RE2_FORCE_STATIC=1
-DWITH_STEMMER=1 -DWITH_STEMMER_FORCE_STATIC=1 -DWITH_ICU=1 -DWITH_ICU_FORCE_STATIC=1 -DWITH_SSL=1 -DWITH_ZLIB=1 -DWITH_ODBC=1 -DDL_ODBC=1
-DODBC_LIB=libodbc.so.2 -DWITH_EXPAT=1 -DDL_EXPAT=1 -DEXPAT_LIB=libexpat.so.1 -DWITH_ICONV=1 -DWITH_MYSQL=1 -DDL_MYSQL=1
-DMYSQL_LIB=libmariadb.so.3 -DWITH_POSTGRESQL=1 -DDL_POSTGRESQL=1 -DPOSTGRESQL_LIB=libpq.so.5 -DLOCALDATADIR=/var/lib/manticore/data
-DFULL_SHARE_DIR=/usr/share/manticore
Manticore Buddy 是一个为 Manticore Search 编写的 PHP 辅助程序,帮助处理各种任务。典型的工作流程是在向用户返回错误之前,Manticore Search 会询问 Buddy 是否能为守护进程处理该问题。Buddy 的 PHP 代码使实现不需要极高性能的高级功能变得容易。
如需更深入了解 Buddy,请查看以下文章:
- 介绍 Buddy:Manticore Search 的 PHP 辅助程序
- Manticore Buddy:挑战与解决方案
- Manticore Buddy:可插拔设计
- Manticore Buddy GitHub 仓库
如果您按照上述安装说明或网站上的说明操作,则无需担心安装或启动 Manticore Buddy:在安装 manticore-extra 软件包时,它会自动安装,并且 Manticore Search 会在启动时自动启动它。
要禁用 Manticore Buddy,请使用 buddy_path 设置。
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,为了对主表应用 kill-list,查询顺序必须是主表先,然后是增量表(无论是在分布式表中还是在 FROM 子句中)。
在 Manticore 3 中,杀死列表(kill-lists)会在 searchd 启动时加载表或进行轮换时应用到表上。表配置中的新指令 killlist_target 指定目标表,并定义应从源表中使用哪些文档 ID 进行抑制。这些可以是定义的杀死列表中的 ID、表的实际文档 ID,或两者。
杀死列表中的文档会从目标表中删除,即使搜索不包括提供杀死列表的表,这些文档也不会出现在结果中。因此,搜索表的顺序不再重要。现在,delta, main 和 main, delta 将提供相同的结果。
在以前版本中,表轮换遵循配置文件中的顺序。在 Manticore 3 中,表的轮换顺序更智能,并且符合 killlist 目标。启动轮换表之前,服务器会通过 killlist_target 定义查找表链。然后它会首先轮换未被作为杀死列表目标引用的表。接下来,它会轮换被已轮换表所针对的表,依此类推。例如,如果执行 indexer --all 并且有 3 个表:main,delta_big(针对 main)和 delta_small(针对 delta_big),则首先轮换 delta_small,然后轮换 delta_big,最后轮换 main。这是为了确保当依赖的表被轮换时,能从其他表获取最新的杀死列表。
docinfo- 现在一切都是 externinplace_docinfo_gap- 不再需要mva_updates_pool- MVAs 不再有专门的更新池,因为现在它们可以直接在 blob 中更新(见下文)。
字符串、JSON 和 MVA 属性可以通过 Manticore 3.x 中的 UPDATE 语句更新。
在 2.x 中,字符串属性需要使用 REPLACE,JSON 只能更新标量属性(因为它们是定长的),MVA 可以通过 MVA 池来更新。现在更新直接在 blob 组件上执行。可能需要调整的一个设置是 attr_update_reserve,该设置允许更改在 blob 末尾为避免频繁调整大小而分配的额外空间大小,当新值比现有 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(命中列表)文件,这是唯一在新格式中没有任何更改的表组件。
你可以使用 -–output-dir 选项将新表版本保存到不同文件夹。
$ index_converter --config /home/myuser/manticore.conf --all --output-dir /new/path
杀死列表表是特殊情况。由于杀死列表行为已更改(参见 killlist_target),增量表应知道用于应用杀死列表的目标表。有 3 种方法可以将转换后的表准备好设置应用杀死列表的目标表:
- 转换表时使用
-–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 使用指定的文件作为配置文件。通常,它会在安装目录中查找 manticore.conf(例如,如果安装在/usr/local/sphinx,则查找/usr/local/manticore/etc/manticore.conf),然后查找调用 index_converter 时所在的当前目录。--index指定要转换的表--path- 不使用配置文件,改为使用包含表的路径--strip-path- 从表引用的文件名中去除路径:stopwords、exceptions 和 wordforms--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
)