我正在研究基于 Grove-Vue 构建的 Vue 应用程序的搜索功能。该应用程序使用 MarkLogic 的 REST API v1/search
两个词搜索的搜索结果(来自大约 200 万个文档和大约 10 个不同的集合)需要 14 秒才能执行。如果 pageLength 设置为 20,则为 28 秒;对于 30 条记录,则为 42 秒。
为了隔离问题,当我在查询控制台中使用
search.search
函数从 MarkLogic 搜索相同的 2 个单词时,大约需要相同的时间。
const search = require('/MarkLogic/appservices/search/search');
search.search("one two");
这消除了 UI 层的延迟。有或没有选项的差异可以忽略不计 - 所以选项也不是问题。
我查看了 查询调优文档,并将
query-meters
添加到 search.search
函数中。我看到这个:
"elapsedTime": "PT14.190265S",
"requests": 0,
"listCacheHits": 53,
"listCacheMisses": 18,
"listSize": 73324,
"inMemoryListHits": 0,
"tripleCacheHits": 0,
"tripleCacheMisses": 0,
"tripleValueCacheHits": 0,
"tripleValueCacheMisses": 0,
"expandedTreeCacheHits": 19,
"expandedTreeCacheMisses": 0,
"compressedTreeCacheHits": 0,
"compressedTreeCacheMisses": 0,
"compressedTreeSize": 0,
"inMemoryCompressedTreeHits": 0,
"valueCacheHits": 35,
"valueCacheMisses": 35,
"regexpCacheHits": 23,
"regexpCacheMisses": 8,
"linkCacheHits": 0,
"linkCacheMisses": 0,
"filterHits": 19,
"filterMisses": 0,
"fragmentsAdded": 0,
"fragmentsDeleted": 0,
"fsProgramCacheHits": 0,
"fsProgramCacheMisses": 0,
"dbProgramCacheHits": 0,
"dbProgramCacheMisses": 0,
"envProgramCacheHits": 0,
"envProgramCacheMisses": 0,
"fsMainModuleSequenceCacheHits": 0,
"fsMainModuleSequenceCacheMisses": 0,
"dbMainModuleSequenceCacheHits": 0,
"dbMainModuleSequenceCacheMisses": 0,
"fsLibraryModuleCacheHits": 0,
"fsLibraryModuleCacheMisses": 25,
"dbLibraryModuleCacheHits": 0,
"dbLibraryModuleCacheMisses": 2,
"readLocks": 0,
"writeLocks": 0,
"lockTime": 0,
"contemporaneousTimestampTime": 0,
"compileTime": 0.210152,
"commitTime": 0,
"runTime": 0,
"indexingTime": 0,
"fsSchemaCacheHits": 0,
"fsSchemaCacheMisses": 0,
"dbSchemaCacheHits": 0,
"dbSchemaCacheMisses": 0,
"envSchemaCacheHits": 16184,
"envSchemaCacheMisses": 0,
"fragments": [
],
...
还使用了
query-trace
,这是输出
2024-01-22 16:13:07.072 Info: /MarkLogic/appservices/search/search-impl.xqy at 2666:37: impl:apply-search(map:map(<map:map xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" .../>), (), fn:false())
2024-01-22 16:13:07.072 Info: /MarkLogic/appservices/search/search-impl.xqy at 2666:37: Analyzing path for search: fn:collection()
2024-01-22 16:13:07.072 Info: /MarkLogic/appservices/search/search-impl.xqy at 2666:37: Step 1 is searchable: fn:collection()
2024-01-22 16:13:07.072 Info: /MarkLogic/appservices/search/search-impl.xqy at 2666:37: Path is fully searchable.
2024-01-22 16:13:07.072 Info: /MarkLogic/appservices/search/search-impl.xqy at 2666:37: Gathering constraints.
2024-01-22 16:13:07.072 Info: /MarkLogic/appservices/search/search-impl.xqy at 2666:37: Search query contributed 2 constraints: cts:and-query((cts:word-query("one", ("lang=en"), 1), cts:word-query("two", ("lang=en"), 1)), ())
2024-01-22 16:13:07.072 Info: /MarkLogic/appservices/search/search-impl.xqy at 2666:37: Executing search.
2024-01-22 16:13:07.077 Info: /MarkLogic/appservices/search/search-impl.xqy at 2666:37: Selected 24292 fragments to filter
检查了 ErrorLog.txt 文件中的查询跟踪输出,没有不可搜索的步骤。
查询仪表输出中存在相当多的缓存未命中。文档然后说
cache misses indicate that the query might be able to be optimized, either by rewriting the parts of the query that have cache misses to better take advantage of the indexes or by adding indexes that the query can use.
因为应用程序使用 MarkLogic Rest API,所以我的假设是我认为我无法优化查询。有没有办法进一步优化这个查询?
如果没有,那么我需要对索引做什么,以便查询可以使用索引?
假设缓存未命中是搜索缓慢的唯一原因。请问这里有什么指点吗?
服务器规格(磁盘空间、RAM 等)符合 MarkLogic 的建议。
编辑: 该选项指定
<search-option>unfiltered</search-option>
- 所以你是对的,搜索未过滤。重新运行搜索时存在非常微小的差异。
整个 MarkLogic(安装、林、日志等)的磁盘使用量约为 300G - 因此文档大小不是很大。
搜索结果时间及建议:
默认: PT13.944414S
返回结果为假: PT0.233757S
返回结果 false 且代码片段 = raw(而不是 = apply): PT0.02006S
只需使用 snippet = raw(而不是 = apply): PT12.063621S
所以看起来确实大部分时间都花在生成片段上。有什么办法可以加快速度吗
这些是作为选项传入的片段:
<transform-results apply="snippet">
<preferred-matches>
<element ns="http://marklogic.com/entity-services" name="instance"/>
</preferred-matches>
<max-matches>1</max-matches>
<max-snippet-chars>1000</max-snippet-chars>
<per-match-tokens>20</per-match-tokens>
</transform-results>
<return-query>1</return-query>
<!-- This controls the snippet size toggle -->
<operator name="results">
<state name="compact">
<transform-results apply="snippet">
<preferred-matches>
<element ns="http://marklogic.com/entity-services" name="instance"/>
<json-property>instance</json-property>
</preferred-matches>
<max-matches>5</max-matches>
<max-snippet-chars>2000</max-snippet-chars>
<per-match-tokens>100</per-match-tokens>
</transform-results>
</state>
<state name="detailed">
<transform-results apply="snippet">
<preferred-matches>
<element ns="http://marklogic.com/entity-services" name="instance"/>
<json-property>instance</json-property>
</preferred-matches>
<max-matches>5</max-matches>
<max-snippet-chars>2000</max-snippet-chars>
<per-match-tokens>100</per-match-tokens>
</transform-results>
</state>
</operator>
听起来大部分时间都来自于阅读文档中的片段。
如果读取和处理搜索结果中的 10 个文档需要 10-15 秒,我就会怀疑文档的大小和/或集群的容量。
如果搜索速度很快,但处理文档很慢(比您想要的要慢),您可以尝试将搜索与片段分开。
例如,使用
apply="empty-snippet"
返回信息来支持工作,然后在返回搜索后执行此操作以异步装饰结果?
https://docs.marklogic.com/guide/search-dev/query-options#id_58295
选项不返回结果节点,但会为每个搜索结果返回一个空的搜索:片段元素。 search:result 包装元素确实具有访问节点并对匹配的搜索节点执行您自己的转换所需的信息(例如,节点的 URI 和路径),因此您可以在外部编写自己的代码搜索 API 来处理结果。apply="empty-snippet"