siyuan-note / siyuan

A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang.
https://b3log.org/siyuan
GNU Affero General Public License v3.0
22.91k stars 1.61k forks source link

改进搜索排序规则 #4546

Closed 88250 closed 2 years ago

88250 commented 2 years ago

在考虑匹配度的同时考虑 3 个类型:文档 > 标题 > 列表项

fanglypro commented 2 years ago

问题1:现在列表项和文档块的搜索结果都不会高亮,以及现在的块引搜索显示速度貌似比之前慢了一些:

image

image

问题2:对于搜索结果中的列表项,之前是在搜索界面显示全content的内容,1.9.8中应该是因为 https://github.com/siyuan-note/siyuan/issues/4536 这个 issue 导致不止是锚文本,搜索结果界面中也只显示了第一个块的content,这里应该还是和之前一样显示全content,不然可能会导致搜索结果中不同的列表项无法直接区分,不方便选择。

问题3:搜索结果的排序规则还是有问题

改进后的规则是在匹配度相同的情况下,再根据块类型排序吗?

现在的规则之下,有一些问题:

  1. 把匹配度放在第一位在思源中并不合适,因为思源的块太多了,一上来就按匹配度容易出问题。只有文档块和标题块时,按照匹配度没问题,一旦有了列表项,问题就变得复杂了。第一个例子是上面的图片,在笔记里面有大量只包含关键字的块的时候(这在写列表的过程中常见),搜索结果的前列会被这些块所淹没,找不到重要的文档块,和https://github.com/siyuan-note/siyuan/issues/4534#issuecomment-1092836329 里面我说的问题一样,这个issue并不能改善昨天提的问题。第二个例子见下图,这里的核心问题在于,文档块和标题块的content字段不包含子项,然而列表项的content字段是包含子项的,我想要搜的内容是红框中的父结点,但排序第一个的是在叶子结点的列表项,显然在叶子结点的列表项包含信息是最少的,排在第一个不合理,我上面的多任务的图片也是一样,排在前列的全部都是叶子结点的列表项,这些列表项所含有的信息量是垫底的,排在前面没有意义。

image

  1. 由于列表项的content字段是包含子项的,所以也导致length字段有问题,下图中在子层的列表项length更小信息量更少,却排在顶层的列表项之前,之所以在块类型中文档块>标题块>列表项,是按照信息量期望值从大到小,但是在列表项中,因为content的问题,导致匹配度排序失效,只能往下面看length,而length越小,列表项信息量期望值越小,length越大的列表项才是最外层,再加上列表的content会套娃,叶子结点的列表项命中会接连着带来大量的搜索召回,搜索结果容易变成灾难,按现在的排序算法,会根本找不到目标结果。

image

我的搜索排序规则想法如下,供参考:先按sort字段(我不太清楚sort的具体计算公式,是否可以公布一下呢?但按我之前的体验,应该至少满足了文档块优先级>标题块),然后按匹配度(对于列表块,希望能优化一下,不是直接匹配列表项本身的content,而是匹配列表项的第一个块的content),然后是命中次数(我记得之前是有这个指标的,没有的话忽略也行),然后是按length从小到大,之后其他指标

同时,在进行搜索召回时,对列表项判断是否要召回时,不按照列表项本身的content判断,而是按照列表项的第一个块的content进行判断,这样能保证搜索结果是最小可用的,使得搜索结果更加简洁清晰。因为列表项的content会套娃,会带来很多无意义的召回结果,例如下图,红框中的这些召回结果都是没意义的:

image

我再给几个案例,我认为排序规则应当能满足这几个案例的要求:

案例1:先新建一个文档叫做《多任务学习》,然后在这个文档内写上:

* abc
  * def
    * 思路
      * 多任务 
    * 思路
      * 多任务

这时,我块引搜索[[多任务的时候,排在第一个的应该是《多任务学习》这个文档

案例2:

在任意文档内写上:

* 概述
  * 一些典型的工作例如PNN,Wide&Deep,NFM,DeepFM,xDeepFM,DIN等
* Wide&Deep
  * Wide&Deep 是由Google于2016年提出的,是推荐领域取得较大成功的最早深度模型
  * 在Wide&Deep的框架下,一个优势是Wide部分可以沿用之前非深度特征交互的成果,尤其是特征工程部分

这时候块引搜索[[Wide&Deep时,排序在第一个的应该是* Wide&Deep打头的这个父级列表项

其实 https://ld246.com/article/1649338100756 这个帖子中的需求和排序有很大的关系,如果他想要的结果就在第一个或者第二个,那么他的需求就满足了,并不需要对块引搜索的交互做其他的改进,而现在的搜索排序有问题,导致他在帖子里说“块引搜索框目前不显示列表块和列表项块”、“搜索结果里只显示段落块”。

88250 commented 2 years ago

问题 1 先略过。

问题 2 单独建个 issue https://github.com/siyuan-note/siyuan/issues/4555

我们重点讨论问题 3。现在的实现大致是这样的 SQL:

select *
from blocks
where ((content like '%foo%' or name like '%foo%' or alias like '%foo%' or memo like '%foo%'))
  and type IN ('d', 'h', 'c', 'm', 't', 's', 'p', 'html', 'iframe', 'query_embed', 'video', 'audio', 'widget')
order by case
             when name = 'foo' then 10
             when alias = 'foo' then 20
             when memo = 'foo' then 30
             when content = 'foo' and type = 'd' then 31
             when content = 'foo' and type = 'h' then 32
             when content = 'foo' and type = 'i' then 33
             when content = 'foo' then 40
             when name LIKE '%foo%' then 50
             when alias LIKE '%foo%' then 60
             when memo LIKE '%foo%' then 70
             when content LIKE '%foo%' and type = 'd' then 71
             when content LIKE '%foo%' and type = 'h' then 72
             when content LIKE '%foo%' and type = 'i' then 73
             when content LIKE '%foo%' then 80
             else 65535 end ASC, sort ASC, length ASC
limit 64

sort 字段是定值:

改进的话 blocks 表现有字应该不够,缺乏容器块第一个子块的 content 字段 fcontent,通过这个字段做 length 排序,如果是容器块的话过滤也需要在 fcontent 而非 content 上做。

老铁有空的话可以基于上面这个 SQL 帮忙改改看,谢谢。

88250 commented 2 years ago

对了,改造以后,多任务学习那个案例如果是在自身文档中块引搜索的话,会排除自身文档名命中,只有在其他文档中块引搜索时才会排第一个。

image