当用户输入存在名称时,
我需要快速向用户提示可用名称。
在前端,没有问题。
但在后端,如何编写敏锐的代码?
这个功能就像用户使用名称'Java'注册一个电子邮件帐户一样,当发现重复时,会给用户一些可用的名称建议,如'Java01','Java001','Java002'
目前,我的想法如下, 示例:
用户输入名称为“ Name01 ”
首先,我使用'JPQL(JPA)'来验证名称是否存在;
如果存在,我将创建一个类似'Select name from table a where a.name like 'Name01%'
的sql
然后我会得到一个存在名单。{'Name012','Name014','Name015'...}
所以我使用'Name01'来一般猜测列表
比如{'Name010','Name011','Name012','Name013','Name014',...}
然后我使用猜测列表来比较存在的名称列表,并返回一个10大小的列表(不应该存在于db中,用户可以使用其中一个来快速保存请求)避免第二次验证。)像:{'Name010','Name011','Name013','Name016',...}
但是如果猜测列表全部存在于db中。
我需要通过'Name0%'搜索db并执行
递归。
看起来效率很低。
我很困惑如何一般的猜测列表以及如何比较会降低比较频率。
有谁有好的解决方案?
提示:我使用JSF + EJB + JPA(Eclipse Link 1.0)DB2名称的最大长度为10,只能包含字符。
答案 0 :(得分:2)
在这种情况下使用的高效数据结构是Trie
(前缀树)。
作为应用程序的一部分,您应生成包含所有Trie
的{{1}},并且此数据结构可用于生成用户提示。这种数据结构的优点在于它将时间复杂度降低到Name
。
例如:name0,name10,name45将生成具有以下节点的Trie
O(n)
答案 1 :(得分: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
所以只需先定义一条规则来生成建议列表的规则,并使该算法第一次接近成功,并且建议接近用户的需求。
答案 2 :(得分:0)
正如Byter所指出的,Trie
是最佳的对象类型。但是,找到一个易于使用的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;
(不要忘记重建数据库架构)或发出native query。
答案 3 :(得分:0)
如果我理解正确,您只需几步: 1)用户输入他们的首选userName(没有限制的自由文本条目,可能很少规则) 2)您从上面验证用户输入,如果它是唯一的或当前用户没有其他选择,则接受它(此时是否禁用用户自由文本输入?) 3)您接受来自步骤2)的用户选择(没有进一步验证,因为您认为它已经是唯一的吗?)
在没有验证的情况下承担任何事情并接受任何用户数据绝对不是一个好主意,因此步骤3)必须执行与步骤2)相同的验证 - 这意味着没有步骤3),有只是重复一步2)。
在第2步中留下功能
查询您的用户存储(DB)以检查该条目是否唯一:
a)它是唯一的 - 创建新条目并通知用户
b)它已经存在 - 查询你的用户商店的LIKE条目,通常是userEnteredStringFromStep1 + someWayOfMakingYourStringUnique。最常见的someWayOfMakingYourStringUnique只是一个数字。因此,您需要在LIKE'userEnteredStringFromStep1%'中查询您的用户存储,并生成新的userEnteredStringFromStep1 + someWayOfMakingYourStringUnique组合,这些组合在您的结果中不存在。