IBM Domino Java优化:提升$(Rooms)视图特定互联网地址搜索效率
嘿,我完全理解你现在的困扰——遍历整个$(Rooms)视图来逐个查找会议室文档,这种线性扫描在处理批量请求时效率肯定拉胯,50个查询花18秒确实没法接受。咱们来把这个逻辑彻底优化一下,利用Domino的视图索引和搜索能力来大幅提升速度。
问题根源
你当前的代码用ViewNavigator从头到尾遍历所有视图条目,本质是线性扫描,如果视图里有上百甚至上千个会议室条目,每次查询都要走一遍全量数据,性能自然差。Domino的视图本身是带索引的,咱们要直接利用这个索引来做精准查询,而不是手动遍历。
优化方案1:使用公式搜索(快速实现,无需修改视图)
如果不想改动系统自带的$(Rooms)视图,最快捷的方式是用Domino的Database.search()方法,通过公式直接筛选出匹配InternetAddress的文档,跳过全量遍历:
Session session = ExtLibUtil.getCurrentSession(); Database names = session.getDatabase(session.getServerName(), "names.nsf"); // 构建精确匹配的搜索公式,注意转义双引号 String escapedMail = mail.replace("\"", "\"\""); String searchFormula = "InternetAddress = \"" + escapedMail + "\""; // 执行搜索,直接拿到匹配的文档集合 DocumentCollection dc = names.search(searchFormula); Document docRoom = null; if (dc.getCount() > 0) { docRoom = dc.getFirstDocument(); } // 后续获取会议室信息的逻辑不变 if(docRoom == null) { dc.recycle(); return null; } String fileName = docRoom.getItemValueString("MailFile"); String fileServer = docRoom.getItemValueString("MailServer"); String fullName = docRoom.getItemValueString("FullName"); // 务必回收资源,避免内存泄漏 dc.recycle(); docRoom.recycle(); names.recycle();
这种方式会直接利用Domino的索引能力,查询速度会比遍历快几个数量级。
优化方案2:创建自定义视图(性能最优推荐)
如果你的应用需要频繁做这类查询,建议创建一个自定义视图(不要修改系统自带的$(Rooms)视图,避免升级或系统变更时出问题),把InternetAddress设为第一列并勾选“排序”和“为列创建索引”。
假设你创建的视图名为(RoomsByInternetAddress),代码可以改成:
Session session = ExtLibUtil.getCurrentSession(); Database names = session.getDatabase(session.getServerName(), "names.nsf"); View vw = names.getView("(RoomsByInternetAddress)"); // 利用视图索引直接获取匹配的文档,true表示精确匹配 Document docRoom = vw.getDocumentByKey(mail, true); if(docRoom == null) { vw.recycle(); names.recycle(); return null; } String fileName = docRoom.getItemValueString("MailFile"); String fileServer = docRoom.getItemValueString("MailServer"); String fullName = docRoom.getItemValueString("FullName"); // 回收资源 docRoom.recycle(); vw.recycle(); names.recycle();
这种方式是性能最优的,因为getDocumentByKey直接命中视图索引,几乎是O(1)的查询时间。
批量查询的额外优化
你需要处理50个会议室,建议一次性批量查询所有需要的邮件地址,而不是逐个查询,减少和names.nsf的交互次数。比如:
// 假设mails是包含50个会议室邮件地址的List<String> List<String> mails = Arrays.asList("room1@domain.com", "room2@domain.com", ...); // 构建批量查询公式 StringBuilder formulaBuilder = new StringBuilder("@In(InternetAddress; ["); for(int i=0; i<mails.size(); i++) { if(i > 0) formulaBuilder.append(";"); formulaBuilder.append("\"").append(mails.get(i).replace("\"", "\"\"")).append("\""); } formulaBuilder.append("])"); DocumentCollection dc = names.search(formulaBuilder.toString()); // 遍历文档集合,把结果缓存到Map里(key=InternetAddress,value=会议室信息) Map<String, RoomInfo> roomCache = new HashMap<>(); Document doc = dc.getFirstDocument(); while(doc != null) { String addr = doc.getItemValueString("InternetAddress"); RoomInfo info = new RoomInfo(); info.setMailFile(doc.getItemValueString("MailFile")); info.setMailServer(doc.getItemValueString("MailServer")); info.setFullName(doc.getItemValueString("FullName")); roomCache.put(addr, info); Document nextDoc = dc.getNextDocument(doc); doc.recycle(); doc = nextDoc; } dc.recycle(); // 后续处理直接从缓存取 for(String mail : mails) { RoomInfo info = roomCache.get(mail); // 处理约会逻辑 }
这样一次查询就能拿到所有需要的会议室信息,避免了50次单独的数据库请求,性能会再上一个台阶。
额外注意事项
- 资源回收:Domino的Java对象(Session、Database、View、Document等)必须手动回收,否则会导致内存泄漏,长期运行会影响服务器性能。
- 索引检查:确保
InternetAddress字段在names.nsf中被索引(可以在数据库属性的“全文索引”或视图列索引里配置),这样搜索会更快。
内容的提问来源于stack exchange,提问作者AJ Cole

