`
mozhenghua
  • 浏览: 324447 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

集合聚合算法

 
阅读更多

       有这样一个需求,在做solr索引优化的设计方案中,业务方给出了一个业务场景,相关的业务表有n多张,需要出一个方案来解决数据库上复杂SQL查询导致的高延时问题,另外顺带通过Solr还需要对一些字段做拼音查询。

     

      利用Solr的倒排索引对数据库的复杂查询是非常奏效的,另外,可以在Solr上事先将数据库中的几张业务表打成宽表的方式,进一步提高查询效率。打宽表是一种常用的优化手段,但是,子业务逻辑表不能太多,太多的话,会造成索引更新维护非常麻烦(如果索引不需要更新的话,那么聚合的子表再多也没有问题),按照笔者的经验,宽表的子表数不能超过5张为宜。

      

      需求分析时,让业务方给出了一份在查询数据库上的一些复杂SQL,大都是有left outer join 的SQl,而且关联的表还不止一个。算了一下,关联到的表有14个,当然不能将这14个表聚合成一个宽表,需要分而治之,将这一堆表切分成相对小的宽表(每个宽表一个solr的collection),这样维护起来相对方便一些。

    首先,拿到了以下一份表之间的查询关联关系:

    

"kind_menu_addition
kind_menu
menu"
"kind_menu_addition
kind_menu"
"menu_make
make
menu"
"kind_menu
menu"
"menu
kind_menu
menu_spec_detail
menu_make"
"menu
kind_menu
menu_prop"
"menu_make
make"
"menu_spec_detail
spec_detail"
"menu_time_price
menu
kind_menu"
"menu_spec_detail
spec_detail
menu"
"suit_menu_detail
menu"
"suit_menu_change
suit_menu_detail
menu
spec_detail"
"suit_menu_detail
menu"
"kind_menu
menu_kind_taste"
"menu_kind_taste
kind_taste"
"menu_kind_taste
kind_taste
taste"
"menu_kind_taste
taste"

 

     如上,引号之间描述的是,表之间的关联关系,需要有一个算法,将以上的关联描述关系,计算出有关联关系的表簇。类似,A和B有关联关系,A和C也是有关联关系,那么计算结果应该要得到 A,B,C是一个关联簇。

  

     另外需要说明的是,上面描述关系中menu,kind_menu两个表的出现频率非常高。其实menu表是ER关系的主表,所以需要在计算过程中需要将类似于这样的出现频率高的主表过滤掉。

 

 下面给出具体的算法:

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;
import org.apache.commons.lang.StringUtils;

public class TabClusterStatis {
	private static Set<String> mainTables = new HashSet<String>();
	static {
		// 主表
		mainTables.add("menu");
		mainTables.add("kind_menu");
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {

		// 记录每个表和其他表的应用关系
		Map<String, TableLink> tabcluster = new HashMap<String, TableLink>();
		LineIterator it = FileUtils.lineIterator(new File("D:\\tmp\\tab.txt"));

		// 计算表之间的引用关系
		String tab = null;
		Set<String> tables = null;
		TableLink tlink = null;
		while (it.hasNext()) {
			tab = it.nextLine();
			if (StringUtils.startsWith(tab, "\"")) {
				tables = new HashSet<String>();
				tab = StringUtils.substringAfter(tab, "\"");
			}
			boolean endWithSlash = false;
			if (endWithSlash = StringUtils.endsWith(tab, "\"")) {
				tab = StringUtils.substringBefore(tab, "\"");
			}

			tables.add(tab);

			if (endWithSlash) {
				for (String t : tables) {
					tlink = tabcluster.get(t);
					if (tlink == null) {
						tlink = new TableLink(t);
						tabcluster.put(t, tlink);
					}
					tlink.refs.addAll(tables);
				}
			}
		}

		// 将主表删除不参与计算
		Iterator<String> nameIt = tabcluster.keySet().iterator();
		while (nameIt.hasNext()) {
			if (mainTables.contains(nameIt.next())) {
				nameIt.remove();
			}
		}

		List<TableLink> tablelist = new ArrayList<TableLink>(
				tabcluster.values());

		TableLink tref1 = null;
		TableLink tref2 = null;
		Set<String> subsetTable = null;
		List<Set<String>> subsetList = new ArrayList<Set<String>>();
		for (int i = 0; i < tablelist.size(); i++) {

			tref1 = tablelist.get(i);
			if (tref1.hasSetsubWithOther) {
				continue;
			}
			subsetTable = new HashSet<String>();
			// subsetTable.add(String.valueOf(i));
			subsetTable.addAll(tref1.refs);
			subsetList.add(subsetTable);

			for (int j = (i + 1); j < tablelist.size(); j++) {
				tref2 = tablelist.get(j);
				if (tref2.hasSetsubWithOther) {
					continue;
				}
				if (tref2.hasSubSet(subsetTable)) {
					// subsetTable.add("j:" + String.valueOf(j));
					subsetTable.addAll(tref2.refs);
					tref2.hasSetsubWithOther = true;
				}
			}

			for (int jj = tablelist.size() - 1; jj >= (i + 1); jj--) {
				tref2 = tablelist.get(jj);
				if (tref2.hasSetsubWithOther) {
					continue;
				}
				if (tref2.hasSubSet(subsetTable)) {
					// subsetTable.add("jj:" + String.valueOf(jj));
					subsetTable.addAll(tref2.refs);
					tref2.hasSetsubWithOther = true;
				}
			}
		}

		List<String> sortTables = null;
		for (Set<String> c : subsetList) {
			sortTables = new ArrayList<>(c);
			Collections.sort(sortTables);

			for (String t : sortTables) {
				// if (mainTables.contains(t)) {
				// continue;
				// }
				System.out.print(t + ",");
			}
			System.out.println();
		}
	}
	private static class TableLink {
		private final String name;
		private final Set<String> refs = new HashSet<String>();

		boolean hasSetsubWithOther = false;

		public TableLink(String name) {
			super();
			this.name = name;
		}

		boolean hasSubSet(TableLink refs) {
			return hasSubSet(refs.refs);
		}

		public boolean hasSubSet(Set<String> refs) {
			for (String tab : refs) {
				if (mainTables.contains(tab)) {
					continue;
				}
				if (this.refs.contains(tab)) {
					return true;
				}
			}

			return false;
		}

	}

}

 

 执行之后会打印如下信息:

kind_menu,kind_taste,menu_kind_taste,taste,							
kind_menu,menu,menu_time_price,							
kind_menu,make,menu,menu_make,menu_spec_detail,spec_detail,suit_menu_change,suit_menu_detail,							
kind_menu,kind_menu_addition,menu,							
kind_menu,menu,menu_prop,							

很好,自动将两两描述信息计算出了5个子表簇,现在我们就可以在solr上集群中构建5个collection。

 

很显然,这样的做的好处是快不会错,以前都是拍脑袋跟着感觉走,推而广之,在其他场景下也能用上这个算法。

 

 

分享到:
评论
2 楼 mozhenghua 2016-12-15  
她的酒窝 写道
你好,楼主,将数据库中的几张业务表打成宽表的方式,这个打宽表的意思是把多个表的字段综合在一个表里然后建成索引的意思?


是的,思想就是以空间换时间,在查询的时候可以免去量表之间因为join而开销的io时间,这会大大提速
1 楼 她的酒窝 2016-09-01  
你好,楼主,将数据库中的几张业务表打成宽表的方式,这个打宽表的意思是把多个表的字段综合在一个表里然后建成索引的意思?

相关推荐

    java kmeans聚合算法

    对于n维空间中的坐标点集合,几何中心(重心)是各维度坐标值的平均值。 在Java中实现KMeans算法,首先需要设计几个关键类: - **Point**:表示坐标点,包含x和y坐标,可能扩展为更高维度。 - **Cluster**:表示一...

    各类压缩算法聚合

    本文将深入探讨“压缩算法 集合 java”这一主题,结合Java编程语言,阐述压缩算法的基本原理、常用算法以及如何在Java环境中实现和应用。 首先,压缩算法是一种用于减小数据量的技术,通过消除数据中的冗余信息,...

    多域光网络拓扑聚合算法的设计与仿真

    进一步压缩代表点集合,在坐标系中拟合代表点即拟合楼梯,通过拟合结果构造多域光网络的全连通图,运用获取的星形拓扑实施多域光网络拓扑聚合,实现多域光网络拓扑聚合算法的设计。为了验证算法的相对失真性能设计...

    ThinkPHP聚合支付源码 聚合收银台系统源码

    《ThinkPHP聚合支付源码与聚合收银台系统解析》 在互联网支付领域,聚合支付系统扮演着重要的角色,它整合了多种支付渠道,为商家提供了便捷的收款方式。ThinkPHP作为一款广受欢迎的PHP开发框架,被广泛应用于构建...

    arcgis api for javascript 4.x 聚合

    通过合理设置聚集群的半径、最小聚合点数,以及选择合适的聚合算法,可以在保持视觉效果的同时,降低浏览器的计算负担。 总结,ArcGIS API for JavaScript 4.x的聚合功能是构建高效、直观的地图应用的关键。通过...

    基于Python的算法集合设计源码

    标签“Python 算法集”表明这个项目专注于Python编程语言,并且是一个算法的聚合,可能包括经典的计算机科学算法以及现代数据科学和机器学习算法。“数据科学”标签暗示了这个集合可能包含用于数据分析和建模的工具...

    西门子组态SCALANCE X的链路聚合.pdf

    这个逻辑链路所表现出来的特性是多个物理链路的集合,也就是说,所有参与聚合的链路共同提供一个网络通信通道。在西门子的SCALANCE X系列交换机中,通过链路聚合可以将多个百兆或千兆以太网连接捆绑在一起,实现带宽...

    用java实现的基于网格的聚类算法

    - **数据结构**:使用Java集合框架(如ArrayList或HashMap)存储数据点和网格信息。网格可以用二维数组或链表结构表示。 - **算法设计**:遵循以上步骤,编写处理数据、划分网格、计算统计量和识别聚类的函数。 -...

    算法导论课后习题与思考题答案合集

    总结以上内容,文件提供的知识涉及算法分析、不同排序算法、二叉树结构、红黑树、动态规划、贪心算法、持久化分析以及不相交集合等重要概念和算法。掌握了这些知识点,可以对算法导论有一个较为全面和深入的理解,为...

    元搜-聚合搜索引擎V1.1版

    与V1.0版相比增加/修正了以下功能! 1.修正了搜索页顶部无广告时的搜索框错位! 2.后台增加了SEO外链工具链接! 3.后台增加了LOGO图片更换功能! 4.册除了网页标题上作者的版权信息,同时首页底部版权信息移至...

    链路聚合基本概念原理及配置.doc

    Conversation 概念也与链路聚合技术相关,一个 Conversation 是指由若干个帧组成的一个集合。这可以帮助我们更好地理解链路聚合技术的工作原理。 链路聚合技术的应用场景非常广泛,如: 1. 数据中心之间的互连。 2...

    EAGLE-重叠和层次式社区结构发现算法

    接下来,算法采用聚合框架来逐步合并这些最大团,形成更大的社区。该框架通过计算不同最大团之间的相似性和连接强度来决定哪些团应该被合并。 **3. 模块度扩展** 为了评估所形成的覆盖(即由多个社区组成的整体)...

    小样本环境中用于脑电分类的聚合正则化共同空间模式

    为了解决正则化参数确定的问题,进一步提出了聚合(R-CSP-A)的R-CSP,并将一些R-CSP聚合在一起,给出了一个基于集合的解决方案。提出了一种基于BCI竞争三种竞争算法的数据集IVa的算法。实验表明,在SSS(小样本环境)...

    大数据处理中混合型聚类算法的研究与实现.pdf

    聚类算法的目的是将物理或抽象对象的集合分成由类似的对象组成的多个类。根据划分的方式,聚类算法主要分为基于划分的聚类算法和基于层次的聚类算法。 基于划分的聚类算法,其核心思想是将数据集划分为多个类或簇,...

    大规模网页快速去重算法

    相较于传统的聚类方法,该算法大幅提升了处理速度和判断准确性,尤其适用于处理大规模网页集合。 #### 实验验证与结果 通过大规模网页实验的验证,该算法展现了出色的性能。在测试过程中,不仅处理速度远超传统...

    最小生成树 并行算法(corba)

    最小生成树(Minimum Spanning Tree, MST)是图论中的一个重要概念,主要应用于网络设计、数据通信等领域,用于寻找连接所有顶点的边的集合,使得这些边的总权重最小。在并行计算环境中,利用并行算法解决MST问题...

    JAVA编写的基于文本相似度匹配的文本聚类

    在本文中,我们将深入探讨如何使用Java编程语言实现基于文本相似度匹配的文本聚类算法。文本聚类是自然语言处理领域的一个重要课题,它的目标是将大量无结构的文本数据按照其内在的语义关系划分为不同的类别,使得同...

    自定义聚合函数

    在给定的标题“自定义聚合函数”中,我们可以理解到这个话题是关于如何创建自己的聚合函数来处理数据集合。这篇博客的链接虽然未提供具体内容,但通常会涵盖以下知识点: 1. **聚合函数的基本概念**: 聚合函数是...

Global site tag (gtag.js) - Google Analytics