上山打老虎 发表于 2021-7-18 09:02:49

用Erlang实现的简易名字搜索

游戏中一般都会提供根据输入的字符搜索家族,玩家出来。以往的项目要么只能全匹配,要么是通过mysql的模糊搜索来查询的。新项目中全匹配明显不符合要求,而项目设计又不想为了这个功能而加入mysql来增加复杂度,那么剩下的就只有用erlang来实现搜索了。
想当然的就会想到用mnesia来实现,但mnesia只是个KV,功能并不足以实现需求。自己实现一个完整模糊搜索工作量也不小,还好策划的需求并不复杂。

[*]搜索出来的结果只需几十条用于显示
[*]不需要分页显示
为了快速的完成,因此决定搜索只支持从前往后的匹配。因为名字本来就有限制输入特殊符号,以及长度限制,所以对于玩家来说也不会有太大的影响。结合需求以及这些限制,整体设计方案就变得简单许多了。接下来就是构建索引,首先将名字abc,拆成a,ab,abc,然后将它们都指向abc这个ID。搜索时根据玩家的输入如ab,那么就可以很快的直接找出ab,abc,abd,abcd的对应ID了。删除索引也是如此,生成名字索引列表,然后直接删除表项即可。搜索的目的就是想找到自己查询的信息,但根据前面的设计,当玩家完整输入一个完整名字时,有可能因为该索引值对应的ID列表长度已超出显示上限,而没能返回给玩家。所以需要给全匹配的名字增加一个权重,搜索时优先返回权重高的名字回来,这样整体的搜索结果就可以满足要求了。而至于存储,使用ets的bag类型就最方便了。因为设计方案简单,整体核心代码也就50行左右。
前几天看了下代码还是可以继续优化的,因为显示就20条,就没必要把全部名字都索引了,我只需要保存同个索引的最近40条左右即可。删除时只找权重低的,即非全匹配名字的索引来删。这样可以大大的减少索引量,而且搜索时mnesia:dirty_read不会因返回大量数据而耗费了内存。
方案虽然简单,但缺点也很明显。只能从前往后搜索,对于名字开头有特殊符号的,玩家也只能自己输入,才能搜索,而这些符号一般都不太好找。但能花很少的时间,满足80%的功能需求,还是可以尝试下的。

文档来源:开源中国社区https://my.oschina.net/rongtou/blog/756220
页: [1]
查看完整版本: 用Erlang实现的简易名字搜索