1

现在我有一个要求。

当用户输入存在名称时,我需要快速提示用户可用的名称。而在前端,没有问题。但是在后端,如何编写清晰的代码?

这个功能就像当用户使用名称'Java'注册一个电子邮件帐户时,当发现重复时,会给用户一些可用的名称建议g例如'Java01','Java001','Java002'

目前,我的想法如下, 示例

用户输入名称为“ Name01 ”。
首先,我使用“JPQL(JPA)”来验证名称是否存在;
如果存在,我将创建一个类似 ' 的 sql,Select name from table a where a.name like 'Name01%'
然后我将获得一个存在名称列表。{'Name012','Name014','Name015'...}
所以我使用'Name01'来概括一个猜测列表{'Name010','Name011','Name012','Name013','Name014',...}
,然后我使用猜测列表来比较存在名称列表,并返回一个 10 大小的列表(它不应该存在于数据库中,用户可以使用其中一个来保存快速请求以避免第二次验证。)例如:{'Name010','Name011','Name013','Name016',...}
但是如果猜测列表都存在于数据库中。我需要按“Name0%”搜索 db 并进行递归。

看起来效率太低了。
我很困惑如何概括一个猜测列表以及如何进行比较会降低比较频率。 有人有好的解决方案吗?

提示:我使用 JSF+EJB+JPA(Eclipse Link 1.0) DB2 名称的最大长度为 10,只能包含字符。

4

5 回答 5

2

老实说……我觉得非常令人沮丧的是,非常智能的网络应用程序实际上会建议像 ricky01 或 ricky011 之类的东西。

我们仍然是人类,我们想出昵称的原因是为了避免必须记住 ID,这或多或少是最终会在提供诸如 %01 之类的建议的系统中发生的事情

建议您的用户已经为具有更高可见性的用户名(例如他/她的电子邮件地址)选择了用户名,这不是一个更好的主意吗?

电子邮件根据定义是独一无二的,您可以像 google 一样玩:“如果您输入 email@domain.com”然后首先检查电子邮件是否是他的有效用户名,否则检查整个事情......

我想我要说的是你最终会得到一个用户友好得多的系统。

于 2012-07-27T14:06:21.803 回答
2

在这种情况下使用的高效数据结构是Trie(前缀树)。

作为应用程序的一部分,您应该生成Trie带有所有Names 的 a,并且此数据结构可用于生成用户提示。这种数据结构的美妙之处在于它将时间复杂度降低到O(n).

例如:name0,name10,name45 将产生一个具有以下节点的 Trie

root node - "n"
node Level 1 - "a"
node Level 2 = "m"
node Level 3 = "e"
node Level 4 = "0" , "1" , "4"
node Level 4 = "0" , "5"
于 2012-07-30T11:00:42.543 回答
0

如果我对您的理解正确,您只需几个步骤:1)用户输入他们首选的用户名(没有限制的自由文本输入,可能很少规则)2)您从上面验证用户输入,如果它是唯一的则接受它或向用户提供几个替代方案(此时您是否禁用用户自由文本输入?) 3)您接受步骤 2 中的用户选择)(无需进一步验证,因为您假设它已经是唯一的?)

假设任何事情并接受任何用户数据而不进行验证绝不是一个好主意,因此步骤 3) 必须执行与步骤 2) 相同的验证 - 这意味着没有步骤 3),只是重复第2步)。

这在步骤 2 中留下了功能)

查询您的用户存储 (DB) 以检查条目是否唯一:

a) 它是独一无二的 - 创建新条目并通知用户

b) 它已经存在 - 查询您的用户存储中的 LIKE 条目,通常它将是 userEnteredStringFromStep1 + someWayOfMakingYourStringUnique。最常见的 someWayOfMakingYourStringUnique 只是一个数字。因此,您需要在您的用户存储中查询 LIKE 'userEnteredStringFromStep1%' 并生成新的 userEnteredStringFromStep1 + someWayOfMakingYourStringUnique 组合,这些组合在上面的结果中不存在。

于 2012-08-01T09:43:10.613 回答
0

也许您可以先预先定义生成规则:

例如,如果用户的输入存在,然后您将此输入与一些随机生成的字母和数字连接以生成 10 大小的建议列表,然后使用一个查询来验证它们是否可用。因为这个列表真的很少用不上,大多数时候你会成功,如果没有,就重新生成列表。

userInput = "java"
generate list = {"java01","java02","java03",...}
select count(*) into existence from table a where a.name in (list)
if existence >0 then regenerate else return list

所以只需先定义一个规则来生成建议列表的规则,并使该算法在第一次几乎成功,并且建议接近用户的需求。

于 2012-07-31T09:20:08.113 回答
0

正如 Byter 所指出的,aTrie是最适合使用的对象类型。然而,找到一个易于使用的 Java 实现是很棘手的。采取次优选择,并坚持标准课程,这对于黑客来说怎么样?(假设您的用户使用的是 UTF-8)

import com.google.common.collect.*;
import java.util.*;

public class Subsearch {

    private static final List<String> EXAMPLE_RESULTS = Lists.newArrayList("Name010", "Name011", "Name012", "Name013", "Name014", "Name100");

    public static void main(String[] args) {
        // EXAMPLE_RESULTS is from the DB lookup, also retain the original user string
        // exit if the user didn't add one character to the end of the original string
        SortedSet<String> sorted = Sets.newTreeSet(EXAMPLE_RESULTS);
        String userInput = "Name0";
        String upper = userInput + "\uFFFF";        
        SortedSet<String> trimmed = sorted.subSet(userInput, upper);
        // save "trimmed" and userInput for the next iteration
        // no need to store EXAMPLE_RESULTS anymore
        System.out.println(trimmed);
    }
}

我用以下几点警告这一点:确保您确实需要优化您的查找代码。如果数据库没有受到命中的影响,那么不要引入这个额外的复杂层(需要维护的额外代码以及增加并发问题的可能性)。完全有可能,如果您已经索引了您的数据库,@Column那么数据库实际上可能在Trie内部使用。

顺便说一句,你已经索引了你的列,对吧?如果没有,您可以通过将以下特定于 Hibernate 的注释添加到该字段来实现

@org.hibernate.annotations.Index
@Column
String name;

(不要忘记重建 DB Schema)或发出原生查询

于 2012-07-31T11:42:47.647 回答