ソースを参照

修复导出的人群数量不一致的bug

William 2 年 前
コミット
9e05ceff46

+ 22 - 49
src/main/java/org/springblade/useranalysis/controller/UserExcelController.java

@@ -21,11 +21,9 @@ import org.springblade.useranalysis.dto.param.ExcelExportParam;
 import org.springblade.useranalysis.entity.MidCpidUserId;
 import org.springblade.useranalysis.entity.UserGroupEntity;
 import org.springblade.useranalysis.entity.UserProfileExcelLog;
-import org.springblade.useranalysis.entity.clickhouse.ZUserTagEntity;
 import org.springblade.useranalysis.service.UserGroupService;
 import org.springblade.useranalysis.service.normal.ExcelService;
 import org.springblade.useranalysis.service.normal.MidCpidUserIdService;
-import org.springblade.useranalysis.service.normal.UserGroupRuleService;
 import org.springblade.useranalysis.service.normal.UserProfileExcelLogService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -77,8 +75,7 @@ public class UserExcelController extends BladeController {
 	@Autowired
 	private MidCpidUserIdService cpidUserIdService;
 
-	@Autowired
-	private UserGroupRuleService userGroupRuleService;
+	private final static int EXPORT_MAX_COUNT = 999999;
 
 	@ApiOperation("导出Excel")
 	@RequestMapping(value = "/export", method = RequestMethod.POST)
@@ -87,9 +84,9 @@ public class UserExcelController extends BladeController {
 			return R.fail("缺少参数");
 		}
 
-		if (params.getCount() > 1000000) {
-			log.info("最大导出条数不可超过100万");
-			return R.fail("最大导出条数不可超过100万");
+		if (params.getCount() > EXPORT_MAX_COUNT) {
+			log.info("最大导出条数不可超过999999条");
+			return R.fail("最大导出条数不可超过999999条");
 		}
 
 		String sysUserName = "管理员";
@@ -104,16 +101,18 @@ public class UserExcelController extends BladeController {
 		File dir = new File(excelPath);
 		dir.mkdirs();
 
-		UserGroupEntity userGroupEntity = userGroupService.getById(params.getGroupId());
-		if (userGroupEntity == null) {
+		UserGroupEntity userGroup = userGroupService.getById(params.getGroupId());
+		if (userGroup == null) {
 			return R.fail("人群不存在");
 		}
 
-		String groupName = userGroupEntity.getGroupName();
-		if (StringUtils.isNotBlank(params.getMonthStart()) && StringUtils.isNotBlank(params.getMonthEnd())) {
-			groupName = groupName + "(" + params.getMonthStart() + "-" + params.getMonthEnd() + ")";
-			//此种情况没有计算总数,所以暂定100万条
-			params.setCount(1000000);
+		String groupName = userGroup.getGroupName();
+		if (StringUtils.isNotBlank(params.getMonthStart()) &&
+				StringUtils.isNotBlank(params.getMonthEnd())) {
+			groupName = groupName + "(" + params.getMonthStart() + "-" +
+					params.getMonthEnd() + ")";
+			// // 此种情况没有计算总数,所以暂定999999万条
+			// params.setCount(EXPORT_MAX_COUNT);
 		}
 		UserProfileExcelLog excelLog = new UserProfileExcelLog();
 		excelLog.setId(IdWorker.getId());
@@ -128,48 +127,20 @@ public class UserExcelController extends BladeController {
 		excelLog.setSysUserName(sysUserName);
 		excelLog.setRemark(params.isDesens() ? "脱敏" : "不脱敏");
 
-		return handleExport(excelLog, userGroupEntity, params);
+		return handleExport(excelLog, userGroup, params);
 	}
 
 	/**
-	 * 自动计算并导出前后几个月的画像数据
-	 *
-	 * @param params
-	 * @return
-	 */
-//	private R<Object> handleExportByMonths(UserProfileExcelLog excelLog, UserGroupEntity userGroupEntity,
-//			ExcelExportParam params) {
-//		log.info("基于导入的人群导出前后几个月的数据");
-//		// 基于导入的人群导出前后几个月的数据
-//		String groupName = excelLog.getGroupName() + "(" + params.getMonthStart() + "-" + params.getMonthEnd() + ")";
-//		excelLog.setGroupName(groupName);
-//
-//		JSONObject childRule = JSON.parseObject(userGroupEntity.getRules());
-//		QueryWrapper<ZUserTagEntity> wrapperChild = calculateService.zUserTagParseRuleExport(childRule);
-//		QueryWrapper<ZUserTagEntity> wrapperParent = Wrappers.query();
-//		wrapperParent.ge("THEMONTH_V", params.getMonthStart()).le("THEMONTH_V", params.getMonthEnd());
-//
-//		if (excelLogService.save(excelLog)) {
-//			excelService.excute(params, wrapperChild, excelLog);
-//		} else {
-//			return R.fail("导出失败");
-//		}
-//
-//		return R.success("正在导出");
-//	}
-
-	/**
 	 * 普通的导出
 	 *
 	 * @param params
 	 * @return
 	 */
-	private R<Object> handleExport(UserProfileExcelLog excelLog, UserGroupEntity userGroupEntity,
-			ExcelExportParam params) {
+	private R<Object> handleExport(UserProfileExcelLog excelLog, UserGroupEntity userGroup, ExcelExportParam params) {
 		if (excelLogService.save(excelLog)) {
-//			JSONObject rule = JSON.parseObject(userGroupEntity.getRules());
-			QueryWrapper<ZUserTagEntity> wrapper = userGroupRuleService.parse(userGroupEntity);
-			excelService.excute(params, wrapper, excelLog);
+			// QueryWrapper<ZUserTagEntity> wrapper =
+			// userGroupRuleService.parse(userGroupEntity);
+			excelService.excute(params, excelLog, userGroup);
 		} else {
 			return R.fail("导出失败");
 		}
@@ -241,8 +212,10 @@ public class UserExcelController extends BladeController {
 	}
 
 	@ApiOperation("根据Cpid和月份导出手机号")
-	@ApiImplicitParams({ @ApiImplicitParam(name = "cpid", value = "产品CPID,比如:kuaishou", required = true),
-			@ApiImplicitParam(name = "month", value = "精度到月份的日期,示例:202106", required = true) })
+	@ApiImplicitParams({
+			@ApiImplicitParam(name = "cpid", value = "产品CPID,比如:kuaishou", required = true),
+			@ApiImplicitParam(name = "month", value = "精度到月份的日期,示例:202106", required = true)
+	})
 	@GetMapping("/exportByCpid")
 	public R<Kv> exportByCpid(String cpid, String month) {
 		if (StringUtils.isBlank(cpid) || StringUtils.isBlank(month)) {

+ 48 - 16
src/main/java/org/springblade/useranalysis/mapper/clickhouse/UserTagsMapper.java

@@ -19,11 +19,12 @@ import com.baomidou.mybatisplus.core.toolkit.Constants;
 
 public interface UserTagsMapper extends BaseMapper<ZUserTagEntity> {
 
-//	@Deprecated
-//	List<UserProfileTagView> tagView(@Param("userId") String userId, @Param("month") String month);
-//	
-//	@Deprecated
-//	List<UserProfileTagView> tagView1(@Param("userId") String userId);
+	// @Deprecated
+	// List<UserProfileTagView> tagView(@Param("userId") String userId,
+	// @Param("month") String month);
+	//
+	// @Deprecated
+	// List<UserProfileTagView> tagView1(@Param("userId") String userId);
 
 	List<UserProfileTagView> findTagViewByUserId(@Param("sql") String sql, @Param("userId") String userId);
 
@@ -83,7 +84,7 @@ public interface UserTagsMapper extends BaseMapper<ZUserTagEntity> {
 	@Select("select uniqCombined(USERID_V) as num, ${cName} as tCode from Z_USER_TAG_FLAT_ALL ${ew.customSqlSegment} group by tCode order by num desc")
 	List<Map<String, Object>> groupAnalysis(@Param("cName") String cName,
 			@Param(Constants.WRAPPER) QueryWrapper<ZUserTagEntity> TagWrapper);
-	
+
 	@Select("with toInt32OrZero(THEMONTH_V) as INT_THEMONTH_V\n"
 			+ "select\n"
 			+ "	count(DISTINCT USERID_V) as num,\n"
@@ -107,7 +108,7 @@ public interface UserTagsMapper extends BaseMapper<ZUserTagEntity> {
 			+ "	tCode\n"
 			+ "order by\n"
 			+ "	num desc")
-	List<Map<String, Object>> groupAnalysisBaseImport(String importId,@Param("cName") String cName,
+	List<Map<String, Object>> groupAnalysisBaseImport(String importId, @Param("cName") String cName,
 			@Param(Constants.WRAPPER) QueryWrapper<ZUserTagEntity> TagWrapper);
 
 	/**
@@ -118,7 +119,7 @@ public interface UserTagsMapper extends BaseMapper<ZUserTagEntity> {
 	 */
 	@Select("SELECT DISTINCT USERID_V FROM Z_USER_TAG_FLAT_ALL ${ew.customSqlSegment}")
 	List<String> queryUserIdList(@Param(Constants.WRAPPER) QueryWrapper<ZUserTagEntity> TagWrapper);
-	
+
 	@Select("SELECT\n"
 			+ "	DISTINCT USERID_V\n"
 			+ "from\n"
@@ -137,23 +138,25 @@ public interface UserTagsMapper extends BaseMapper<ZUserTagEntity> {
 			+ "		id = #{importId} ) t2\n"
 			+ "on\n"
 			+ "	t1.USERID_V = t2.phone ${sqlLimit}")
-	List<String> queryUserIdListBaseImport(@Param(Constants.WRAPPER) QueryWrapper<ZUserTagEntity> TagWrapper,String importId,String sqlLimit);
-	
+	List<String> queryUserIdListBaseImport(@Param(Constants.WRAPPER) QueryWrapper<ZUserTagEntity> TagWrapper,
+			String importId, String sqlLimit);
+
 	@Select("SELECT\n"
 			+ "	DISTINCT phone\n"
 			+ "from\n"
 			+ "	USER_EXCEL_IMPORT_PHONE_ALL\n"
 			+ "	where\n"
 			+ "		id = #{importId} ${sqlLimit}\n")
-	List<String> queryUserIdListFromImport(String importId,String sqlLimit);
+	List<String> queryUserIdListFromImport(String importId, String sqlLimit);
 
 	@Deprecated
 	@Select("select * from (select  tCode,COUNT(1) as num FROM (select DISTINCT USERID_V,tCode from Z_USER_TAG array join ${cName} as tCode  ${ew.customSqlSegment}) s group by tCode) k order by num desc")
 	List<Map<String, Object>> groupAnalysisByArray(@Param("cName") String cName,
 			@Param(Constants.WRAPPER) QueryWrapper<ZUserTagEntity> TagWrapper);
 
-//	@Deprecated
-//	List<UserProfileTag2Tree> personalTagView(@Param("userId") String userId, @Param("month") String month);
+	// @Deprecated
+	// List<UserProfileTag2Tree> personalTagView(@Param("userId") String userId,
+	// @Param("month") String month);
 
 	@Deprecated
 	@Select(" Select A.* , du.level_1_name , du.level_2_name from DIC_USERTAG du  LEFT JOIN ( SELECT USERID_V, THEMONTH_V , tId , tCode, tValue FROM Z_USER_TAG array join EVENT_CPNAME.E as tId , EVENT_CPNAME.C as tCode, EVENT_CPNAME.V as tValue ) A on A.tId = du.tag_id")
@@ -166,7 +169,7 @@ public interface UserTagsMapper extends BaseMapper<ZUserTagEntity> {
 	@Select("SELECT ${fields} FROM Z_USER_TAG_FLAT_ALL ${ew.customSqlSegment}")
 	List<Map<String, Object>> exportTagList(@Param("fields") String fields,
 			@Param(Constants.WRAPPER) QueryWrapper<ZUserTagEntity> TagWrapper);
-	
+
 	@Select("SELECT\n"
 			+ "	${fields}\n"
 			+ "from\n"
@@ -186,8 +189,8 @@ public interface UserTagsMapper extends BaseMapper<ZUserTagEntity> {
 			+ "on\n"
 			+ "	t1.USERID_V = t2.phone ${sqlLimit}")
 	List<Map<String, Object>> exportTagListBaseImport(@Param("fields") String fields,
-			@Param(Constants.WRAPPER) QueryWrapper<ZUserTagEntity> TagWrapper,String importId,String sqlLimit);
-	
+			@Param(Constants.WRAPPER) QueryWrapper<ZUserTagEntity> TagWrapper, String importId, String sqlLimit);
+
 	@Select("SELECT\n"
 			+ "	${fields}\n"
 			+ "FROM\n"
@@ -214,4 +217,33 @@ public interface UserTagsMapper extends BaseMapper<ZUserTagEntity> {
 			String monthEnd,
 			@Param(Constants.WRAPPER) QueryWrapper<ZUserTagEntity> childWrapper,
 			String sqlLimit);
+
+	/**
+	 * 人群导出新方法(关联BIZ_USER_GROUP_USERID表)
+	 * 
+	 * @param fields     要查询的字段
+	 * @param groupId    人群ID
+	 * @param monthStart 开始月份
+	 * @param monthEnd   结束月份
+	 * @param sqlLimit   分页子语句
+	 * @return
+	 */
+	@Select("SELECT\r\n"
+			+ "	${fields}\r\n"
+			+ "FROM\r\n"
+			+ "	Z_USER_TAG_FLAT_ALL tag\r\n"
+			+ "GLOBAL INNER JOIN BIZ_USER_GROUP_USERID ur ON\r\n"
+			+ "	tag.USERID_V = ur.user_id\r\n"
+			+ "WHERE\r\n"
+			+ "	ur.user_group_id = #{groupId}\r\n"
+			+ "	and tag.THEMONTH_V >= #{monthStart}\r\n"
+			+ "	and tag.THEMONTH_V <=#{monthEnd}\r\n"
+			+ "ORDER BY tag.USERID_V ASC\r\n"
+			+ "${sqlLimit}")
+	List<Map<String, Object>> exportUserGroup(
+			@Param("fields") String fields,
+			@Param("groupId") String groupId,
+			@Param("monthStart") String monthStart,
+			@Param("monthEnd") String monthEnd,
+			@Param("sqlLimit") String sqlLimit);
 }

+ 12 - 0
src/main/java/org/springblade/useranalysis/service/UserTagsService.java

@@ -44,4 +44,16 @@ public interface UserTagsService extends IService<ZUserTagEntity> {
 			String monthEnd,QueryWrapper<ZUserTagEntity> childWrapper,String sqlLimit);
     
     public List<JSONObject> userTagHisDataListByUserId(String userId, String level2Id, String startMonth, String endMonth);
+
+    /**
+	 * 人群导出新方法(关联BIZ_USER_GROUP_USERID表)
+	 * 
+	 * @param fields     要查询的字段
+	 * @param groupId    人群ID
+	 * @param monthStart 开始月份
+	 * @param monthEnd   结束月份
+	 * @param sqlLimit   分页子语句
+	 * @return
+	 */
+	public List<Map<String, Object>> exportUserGroup(String fields,String groupId,String monthStart,String monthEnd,String sqlLimit);
 }

+ 109 - 52
src/main/java/org/springblade/useranalysis/service/impl/UserTagsServiceImpl.java

@@ -11,6 +11,7 @@ import java.util.Set;
 import java.util.stream.Collectors;
 
 import org.apache.commons.lang3.StringUtils;
+import org.apache.ibatis.annotations.Param;
 import org.springblade.useranalysis.dto.TagHistory;
 import org.springblade.useranalysis.entity.AdsUserprofileTag;
 import org.springblade.useranalysis.entity.TagColumn;
@@ -44,7 +45,7 @@ public class UserTagsServiceImpl extends ServiceImpl<UserTagsMapper, ZUserTagEnt
 
 	@Autowired
 	private UserProfileService userProfileService;
-	
+
 	@Autowired
 	private DynamicQueryMapper dynamicQueryMapper;
 
@@ -52,17 +53,22 @@ public class UserTagsServiceImpl extends ServiceImpl<UserTagsMapper, ZUserTagEnt
 	@Override
 	public List<TagHistory> userTagFlowHisSearch(String userId, String level2Id, String startDate, String endDate) {
 		List<TagHistory> rtHis = new ArrayList<TagHistory>();
-//		TagColumn weiduColumn = userProfileService.getColumName(tagId, null);
+		// TagColumn weiduColumn = userProfileService.getColumName(tagId, null);
 		TagColumn weiduColumn = userProfileService.getColumNameExport(level2Id);
-//        SimpleDateFormat format = new SimpleDateFormat("yyyyMM");
-//        QueryWrapper<ZUserTagEntity> queryWrapper = new QueryWrapper<>();
-//        queryWrapper.eq("USERID_V", userId)
-//                .ge("THEMONTH_V", format.format(start_date))
-//                .le("THEMONTH_V", format.format(end_date));
-//        queryWrapper.select("THEMONTH_V",weiduColumn.columnE, weiduColumn.columnC, weiduColumn.columnV).orderBy(true,true,"THEMONTH_V");
-//        List<Map<String, Object>> maps = baseMapper.selectMaps(queryWrapper);
-		List<Map<String, Object>> maps = baseMapper.findOnceTag(userId, startDate,
-				endDate, weiduColumn.columnC, weiduColumn.columnE, weiduColumn.columnV);
+		// SimpleDateFormat format = new SimpleDateFormat("yyyyMM");
+		// QueryWrapper<ZUserTagEntity> queryWrapper = new QueryWrapper<>();
+		// queryWrapper.eq("USERID_V", userId)
+		// .ge("THEMONTH_V", format.format(start_date))
+		// .le("THEMONTH_V", format.format(end_date));
+		// queryWrapper.select("THEMONTH_V",weiduColumn.columnE, weiduColumn.columnC,
+		// weiduColumn.columnV).orderBy(true,true,"THEMONTH_V");
+		// List<Map<String, Object>> maps = baseMapper.selectMaps(queryWrapper);
+		List<Map<String, Object>> maps = baseMapper.findOnceTag(userId,
+				startDate,
+				endDate,
+				weiduColumn.columnC,
+				weiduColumn.columnE,
+				weiduColumn.columnV);
 		Map<Object, List<Map<String, Object>>> groupMap = maps.stream()
 				.collect(Collectors.groupingBy(item -> item.get("THEMONTH_V")));
 
@@ -74,7 +80,8 @@ public class UserTagsServiceImpl extends ServiceImpl<UserTagsMapper, ZUserTagEnt
 				List<Map<String, Object>> valueList = entry.getValue();
 				for (Map<String, Object> item : valueList) {
 					Map<String, Object> tMaps = JSONObject.parseObject(
-							JSONObject.toJSONString(item.get(weiduColumn.englishName.toUpperCase())), HashMap.class);
+							JSONObject.toJSONString(item.get(weiduColumn.englishName.toUpperCase())),
+							HashMap.class);
 					_tags.addAll((List<String>) tMaps.get("C"));
 					_values.addAll((List<String>) tMaps.get("V"));
 				}
@@ -99,16 +106,22 @@ public class UserTagsServiceImpl extends ServiceImpl<UserTagsMapper, ZUserTagEnt
 
 	@Override
 	public List<JSONObject> userTagHisSearch(String userId, String level2Id, String startDate, String endDate) {
-//		TagColumn weiduColumn = userProfileService.getColumName(tagId, null);
+		// TagColumn weiduColumn = userProfileService.getColumName(tagId, null);
 		TagColumn weiduColumn = userProfileService.getColumNameExport(level2Id);
-//		SimpleDateFormat format = new SimpleDateFormat("yyyyMM");
-//        QueryWrapper<ZUserTagEntity> queryWrapper = new QueryWrapper<>();
-//        queryWrapper.eq("USERID_V", userId).ge("THEMONTH_V", format.format(start_date))
-//                .le("THEMONTH_V", format.format(end_date)).isNotNull(weiduColumn.columnV);
-//        queryWrapper.select("THEMONTH_V",weiduColumn.columnE, weiduColumn.columnC, weiduColumn.columnV).orderBy(true,true,"THEMONTH_V");
-//        List<Map<String, Object>> maps = baseMapper.selectMaps(queryWrapper);
-		List<Map<String, Object>> maps = baseMapper.findOnceTag(userId, startDate,
-				endDate, weiduColumn.columnC, weiduColumn.columnE, weiduColumn.columnV);
+		// SimpleDateFormat format = new SimpleDateFormat("yyyyMM");
+		// QueryWrapper<ZUserTagEntity> queryWrapper = new QueryWrapper<>();
+		// queryWrapper.eq("USERID_V", userId).ge("THEMONTH_V",
+		// format.format(start_date))
+		// .le("THEMONTH_V", format.format(end_date)).isNotNull(weiduColumn.columnV);
+		// queryWrapper.select("THEMONTH_V",weiduColumn.columnE, weiduColumn.columnC,
+		// weiduColumn.columnV).orderBy(true,true,"THEMONTH_V");
+		// List<Map<String, Object>> maps = baseMapper.selectMaps(queryWrapper);
+		List<Map<String, Object>> maps = baseMapper.findOnceTag(userId,
+				startDate,
+				endDate,
+				weiduColumn.columnC,
+				weiduColumn.columnE,
+				weiduColumn.columnV);
 		List<JSONObject> resultList = new ArrayList<JSONObject>();
 
 		Map<Object, List<Map<String, Object>>> groupMap = maps.stream()
@@ -121,7 +134,8 @@ public class UserTagsServiceImpl extends ServiceImpl<UserTagsMapper, ZUserTagEnt
 				List<Map<String, Object>> valueList = entry.getValue();
 				for (Map<String, Object> item : valueList) {
 					Map<String, Object> tMaps = JSONObject.parseObject(
-							JSONObject.toJSONString(item.get(weiduColumn.englishName.toUpperCase())), HashMap.class);
+							JSONObject.toJSONString(item.get(weiduColumn.englishName.toUpperCase())),
+							HashMap.class);
 					List<String> cList = (List<String>) tMaps.get("C");
 					valueSet.addAll(cList);
 				}
@@ -161,17 +175,26 @@ public class UserTagsServiceImpl extends ServiceImpl<UserTagsMapper, ZUserTagEnt
 			// 字符串格式,形如:SELECT USERID_V,THEMONTH_V,TAG_PROVINCE AS tId,TAG_PROVINCE_C as
 			// tCode,TAG_PROVINCE_V as tValue FROM Z_USER_TAG_LAST
 			if (tagColumn.columnType.equalsIgnoreCase("string")) {
-				String columnV = !"string".equalsIgnoreCase(tagColumn.searchType) ? "toString(" + tagColumn.columnV + ")" : tagColumn.columnV;
+				String columnV = !"string".equalsIgnoreCase(tagColumn.searchType)
+						? "toString(" + tagColumn.columnV + ")"
+						: tagColumn.columnV;
 				sql = String.format(
 						"select distinct USERID_V, THEMONTH_V, %s as tId, %s as tCode, %s as tValue from %s",
-						tagColumn.columnE, tagColumn.columnC, columnV, clickhouseTableName);
+						tagColumn.columnE,
+						tagColumn.columnC,
+						columnV,
+						clickhouseTableName);
 			} else { // 数组格式,形如:SELECT USERID_V, THEMONTH_V, tId, tCode,tValue FROM Z_USER_TAG_LAST
 						// array join EVENT_SPNAME.E as tId,EVENT_SPNAME.C as tCode,EVENT_SPNAME.V as
 						// tValue
 				String columnV = !"string".equalsIgnoreCase(tagColumn.searchType) ? "toString(tValue)" : "tValue";
 				sql = String.format(
 						"select distinct USERID_V, THEMONTH_V, tId, tCode, %s from %s array join %s as tId, %s as tCode, %s as tValue",
-						columnV, clickhouseTableName, tagColumn.columnE, tagColumn.columnC, tagColumn.columnV);
+						columnV,
+						clickhouseTableName,
+						tagColumn.columnE,
+						tagColumn.columnC,
+						tagColumn.columnV);
 			}
 			sqlList.add(String.format(sqlFragment, sql));
 		}
@@ -200,7 +223,7 @@ public class UserTagsServiceImpl extends ServiceImpl<UserTagsMapper, ZUserTagEnt
 	 */
 	@Override
 	public JSONObject checkTagNum(String tagId, String startDate, String endDate) {
-//        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+		// SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
 		TagColumn tagColumn = userProfileService.getColumName(tagId, null);
 		String sql = "";
 		String whereSql = "";
@@ -213,7 +236,9 @@ public class UserTagsServiceImpl extends ServiceImpl<UserTagsMapper, ZUserTagEnt
 		if (tagColumn.columnType.equals("string")) {
 			sql = String.format("where %s = '%s' %s", tagColumn.englishName.toUpperCase(), tagId, whereSql);
 		} else { // 列存的是Array
-			sql = String.format("array join %s as t1 where t1.E = '%s' %s", tagColumn.englishName.toUpperCase(), tagId,
+			sql = String.format("array join %s as t1 where t1.E = '%s' %s",
+					tagColumn.englishName.toUpperCase(),
+					tagId,
 					whereSql);
 		}
 		List<JSONObject> tagNumList = baseMapper.checkTagNum(sql);
@@ -237,13 +262,15 @@ public class UserTagsServiceImpl extends ServiceImpl<UserTagsMapper, ZUserTagEnt
 			whereSql = String.format("array join %s as t1 %s ", tagColumn.englishName.toUpperCase(), whereSql);
 		}
 		List<JSONObject> tagNumList = baseMapper.checkTagRatio(columnName, whereSql);
-		if(tagNumList != null && !tagNumList.isEmpty()) {
-			//根据leve2Name查询列表
-			List<AdsUserprofileTag> tagList = userProfileService.list(Wrappers.<AdsUserprofileTag>lambdaQuery().eq(AdsUserprofileTag::getLevel2Name, tagColumn.cnName));
-			Map<String, String> tagName2IdMap = tagList.stream().collect(Collectors.toMap(AdsUserprofileTag::getTagName, AdsUserprofileTag::getTagId));
-			//根据tagName反查tagId
+		if (tagNumList != null && !tagNumList.isEmpty()) {
+			// 根据leve2Name查询列表
+			List<AdsUserprofileTag> tagList = userProfileService.list(
+					Wrappers.<AdsUserprofileTag>lambdaQuery().eq(AdsUserprofileTag::getLevel2Name, tagColumn.cnName));
+			Map<String, String> tagName2IdMap = tagList.stream()
+					.collect(Collectors.toMap(AdsUserprofileTag::getTagName, AdsUserprofileTag::getTagId));
+			// 根据tagName反查tagId
 			tagNumList.forEach(item -> item.put("tagid", tagName2IdMap.get(item.get("tagname"))));
-			//库里面已经不存在该标签值,则不显示
+			// 库里面已经不存在该标签值,则不显示
 			tagNumList.removeIf(it -> StrUtil.isEmpty(it.getString("tagid")));
 		}
 		map.put("list", tagNumList);
@@ -251,43 +278,73 @@ public class UserTagsServiceImpl extends ServiceImpl<UserTagsMapper, ZUserTagEnt
 	}
 
 	public List<Map<String, Object>> exportTagList(String fields, QueryWrapper<ZUserTagEntity> TagWrapper,
-			String importId,String sqlLimit) {
+			String importId, String sqlLimit) {
 		if (StringUtils.isBlank(importId)) {
 			return baseMapper.exportTagList(fields, TagWrapper);
 		}
-		return baseMapper.exportTagListBaseImport(fields, TagWrapper, importId,sqlLimit);
+		return baseMapper.exportTagListBaseImport(fields, TagWrapper, importId, sqlLimit);
 	}
-	
-	public List<Map<String, Object>> exportTagListMonths(String fields,String monthStart,
-			String monthEnd,QueryWrapper<ZUserTagEntity> childWrapper,String sqlLimit){
-		return baseMapper.exportTagListMonths(fields,monthStart,monthEnd, childWrapper,sqlLimit);
+
+	public List<Map<String, Object>> exportTagListMonths(String fields, String monthStart,
+			String monthEnd, QueryWrapper<ZUserTagEntity> childWrapper, String sqlLimit) {
+		return baseMapper.exportTagListMonths(fields, monthStart, monthEnd, childWrapper, sqlLimit);
+	}
+
+	/**
+	 * 人群导出新方法(关联BIZ_USER_GROUP_USERID表)
+	 * 
+	 * @param fields     要查询的字段
+	 * @param groupId    人群ID
+	 * @param monthStart 开始月份
+	 * @param monthEnd   结束月份
+	 * @param sqlLimit   分页子语句
+	 * @return
+	 */
+	public List<Map<String, Object>> exportUserGroup(String fields,String groupId,String monthStart,String monthEnd,String sqlLimit) {
+		return baseMapper.exportUserGroup(fields, groupId, monthStart, monthEnd, sqlLimit);
 	}
 
 	@Override
-	public List<JSONObject> userTagHisDataListByUserId(String userId, String level2Id, String startMonth, String endMonth) {
+	public List<JSONObject> userTagHisDataListByUserId(String userId, String level2Id, String startMonth,
+			String endMonth) {
 		TagColumn tagColumn = userProfileService.getColumNameExport(level2Id);
-		if(tagColumn == null) {
+		if (tagColumn == null) {
 			return null;
 		}
 		String sql = "";
 		String clickhouseTableName = "ads.Z_USER_TAG_FLAT_ALL";
 		if (tagColumn.columnType.equals("string")) {
-			String columnV = !"string".equalsIgnoreCase(tagColumn.searchType) ? "toString(" + tagColumn.columnV + ")" : tagColumn.columnV;
-			sql = String.format("select distinct THEMONTH_V as the_month, %s as tag_id, %s as tag_name, %s as tag_value from %s where USERID_V = '%s'",
-					tagColumn.columnE, tagColumn.columnC, columnV, clickhouseTableName, userId);
+			String columnV = !"string".equalsIgnoreCase(tagColumn.searchType) ? "toString(" + tagColumn.columnV + ")"
+					: tagColumn.columnV;
+			sql = String.format(
+					"select distinct THEMONTH_V as the_month, %s as tag_id, %s as tag_name, %s as tag_value from %s where USERID_V = '%s'",
+					tagColumn.columnE,
+					tagColumn.columnC,
+					columnV,
+					clickhouseTableName,
+					userId);
 		} else { // 列存的是Array
-			String columnV = !"string".equalsIgnoreCase(tagColumn.searchType) ? "toString(tmp_tag_value)" : "tmp_tag_value";
-			sql = String.format("select distinct THEMONTH_V as the_month, tag_id, tag_name, %s as tag_value from %s array join `%s` as tag_id, `%s` as tag_name, `%s` as tmp_tag_value where USERID_V = '%s'", 
-					columnV, clickhouseTableName, tagColumn.columnE, tagColumn.columnC, tagColumn.columnV, userId);
+			String columnV = !"string".equalsIgnoreCase(tagColumn.searchType) ? "toString(tmp_tag_value)"
+					: "tmp_tag_value";
+			sql = String.format(
+					"select distinct THEMONTH_V as the_month, tag_id, tag_name, %s as tag_value from %s array join `%s` as tag_id, `%s` as tag_name, `%s` as tmp_tag_value where USERID_V = '%s'",
+					columnV,
+					clickhouseTableName,
+					tagColumn.columnE,
+					tagColumn.columnC,
+					tagColumn.columnV,
+					userId);
 		}
-		if(startMonth != null && endMonth != null) {
+		if (startMonth != null && endMonth != null) {
 			sql += String.format(" and THEMONTH_V >= '%s' and THEMONTH_V <= '%s'", startMonth, endMonth);
-		}else {
-			//获取半年的数据
+		} else {
+			// 获取半年的数据
 			LocalDate now = LocalDate.now().minusMonths(1);
 			LocalDate halfYear = now.minusMonths(6);
-			sql += String.format(" and THEMONTH_V >= '%s' and THEMONTH_V <= '%s'", DateUtil.format(halfYear.atStartOfDay(), "yyyyMM"), DateUtil.format(now.atStartOfDay(), "yyyyMM"));
-			
+			sql += String.format(" and THEMONTH_V >= '%s' and THEMONTH_V <= '%s'",
+					DateUtil.format(halfYear.atStartOfDay(), "yyyyMM"),
+					DateUtil.format(now.atStartOfDay(), "yyyyMM"));
+
 		}
 		return dynamicQueryMapper.list(sql);
 	}

+ 103 - 87
src/main/java/org/springblade/useranalysis/service/normal/ExcelService.java

@@ -2,10 +2,10 @@ package org.springblade.useranalysis.service.normal;
 
 import java.io.File;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.ThreadPoolExecutor;
@@ -18,8 +18,6 @@ import org.springblade.useranalysis.dto.param.ExcelExportParam;
 import org.springblade.useranalysis.entity.TagColumn;
 import org.springblade.useranalysis.entity.UserGroupEntity;
 import org.springblade.useranalysis.entity.UserProfileExcelLog;
-import org.springblade.useranalysis.entity.clickhouse.ZUserTagEntity;
-import org.springblade.useranalysis.service.UserGroupService;
 import org.springblade.useranalysis.service.UserProfileService;
 import org.springblade.useranalysis.service.UserTagsService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -30,7 +28,6 @@ import com.alibaba.excel.ExcelWriter;
 import com.alibaba.excel.converters.longconverter.LongStringConverter;
 import com.alibaba.excel.util.FileUtils;
 import com.alibaba.fastjson2.JSON;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.github.xiaoymin.knife4j.core.util.StrUtil;
 
 import lombok.extern.slf4j.Slf4j;
@@ -54,9 +51,6 @@ public class ExcelService {
 	@Autowired
 	private UserProfileService userProfileService;
 
-	@Autowired
-	private UserGroupService userGroupService;
-
 	final ExecutorService threadPool = new ThreadPoolExecutor(1, 2, 5, TimeUnit.MINUTES,
 			// 有界队列5000,超过队列长度,无异常抛弃
 			new ArrayBlockingQueue<>(5000), new ThreadFactory() {
@@ -64,18 +58,18 @@ public class ExcelService {
 				public Thread newThread(Runnable r) {
 					Thread thread = new Thread(r);
 					thread.setDaemon(false);
-					thread.setName("AdsMarket-Message-Pool-");
+					thread.setName("Export-User-Group-Pool-");
 					return thread;
 				}
 			}, new ThreadPoolExecutor.DiscardPolicy());
 
-	public void excute(ExcelExportParam params, QueryWrapper<ZUserTagEntity> childWrapper,
-			UserProfileExcelLog excelLog) {
+	public void excute(ExcelExportParam params, UserProfileExcelLog excelLog, UserGroupEntity userGroup) {
 		threadPool.execute(() -> {
 			log.info(excelLog.getId() + " - exporting......");
 			long start = System.currentTimeMillis();
 			try {
-				boolean isSuccess = handle(params, childWrapper, excelLog);
+				ConcurrentHashMap<String, String> mobileMap = new ConcurrentHashMap<>();
+				boolean isSuccess = handle(mobileMap, params, excelLog, userGroup);
 				if (isSuccess) {
 					excelLog.setCount(params.getCount());
 					excelLog.setStatus(UserProfileExcelLogService.STATUS_SUCCESS);
@@ -106,8 +100,8 @@ public class ExcelService {
 		}
 	}
 
-	private boolean handle(ExcelExportParam params, QueryWrapper<ZUserTagEntity> childWrapper,
-			UserProfileExcelLog excelLog) {
+	private boolean handle(ConcurrentHashMap<String, String> mobileMap, ExcelExportParam params,
+			UserProfileExcelLog excelLog, UserGroupEntity userGroup) {
 		boolean isSuccess = true;
 		List<String> codeList = params.getTagList();
 		boolean desens = params.isDesens();
@@ -124,43 +118,47 @@ public class ExcelService {
 			}
 		});
 		fields.append("USERID_V,THEMONTH_V");
+		log.info("export fields is :" + fields.toString());
 		File excelFile = new File(excelLog.getFilePath());
-		ExcelWriter excelWriter = EasyExcel.write(excelFile).registerConverter(new LongStringConverter())
-				.head(buidlHeader(columnList)).build();
-		UserGroupEntity group = userGroupService.getById(params.getGroupId());
-		String importId = group != null ? group.getImportId() : null;
+		ExcelWriter excelWriter = EasyExcel.write(excelFile)
+				.registerConverter(new LongStringConverter())
+				.head(buidlHeader(columnList))
+				.build();
+		String groupId = params.getGroupId();
+		// 使用前端传递的日期范围
+		String monthStart = params.getMonthStart();
+		String monthEnd = params.getMonthEnd();
+
+		// 使用圈定人群的日期范围
+		// String monthStart = "";
+		// String monthEnd = "";
+		// JSONObject rule = JSON.parseObject(userGroup.getRules());
+		// if (rule != null) {
+		// if (rule.containsKey("daterange")) {
+		// JSONArray daterange = rule.getJSONArray("daterange");
+		// if (daterange != null && daterange.size() == 2) {
+		// monthStart = daterange.getString(0);
+		// monthEnd = daterange.getString(1);
+		// }
+		// }
+		// }
 		// 需要导出的数量
 		int count = params.getCount();
-		// 已经查寻的数量
-		int total = 0;
-		// 待查询数量
-		int rest = count - total;
+		log.info("export count need is :" + count);
+		
+		// 已经导出的数量
+		int exportedCountTotal = 0;
+		
 		// 下次查询偏移量
 		int offset = 0;
 
 		while (true) {
 			int pageSize = PAGE_SIZE;
-			if (count <= PAGE_SIZE) {
-				// 如果不足一万条,一次性查完
-				pageSize = count;
-			}
-			if (rest <= PAGE_SIZE) {
-				// 带查询的数量小于等于一万条,一次性查完
-				pageSize = rest;
-			}
-
 			String sqlLimit = "limit " + offset + "," + pageSize;
 			List<Map<String, Object>> tagList = null;
 			try {
-				if (StringUtils.isNotBlank(params.getMonthStart()) && StringUtils.isNotBlank(params.getMonthEnd())) {
-					tagList = userTagsService.exportTagListMonths(fields.toString(), params.getMonthStart(),
-							params.getMonthEnd(), childWrapper, sqlLimit);
-				} else {
-					if (StringUtils.isBlank(importId)) {
-						childWrapper.last(sqlLimit);
-					}
-					tagList = userTagsService.exportTagList(fields.toString(), childWrapper, importId, sqlLimit);
-				}
+				log.info("export limit sql is :" + sqlLimit);
+				tagList = userTagsService.exportUserGroup(fields.toString(), groupId, monthStart, monthEnd, sqlLimit);
 			} catch (Exception e) {
 				log.error("ExcelService handle fail, the error is " + e.getMessage());
 				isSuccess = false;
@@ -172,11 +170,13 @@ public class ExcelService {
 				break;
 			}
 
-			total += tagList.size();
-			rest = count - total;
-			excel(desens, excelWriter, columnList, tagList, excelLog.getGroupName());
-			if (total == count || tagList.size() < pageSize) {
-				// 当前已经是最后一页
+			// 本次去重后导出的数量
+			int exportedCountCur = excel(mobileMap, desens, excelWriter, columnList, tagList, excelLog.getGroupName());
+			exportedCountTotal += exportedCountCur;
+			if (exportedCountTotal == count || tagList.size() < pageSize) {
+				// 导出数量完成 或者 已经查询完成
+				log.info("export exportedCountTotal is :" + exportedCountTotal);
+				log.info("export tagList.size() is :" + tagList.size());
 				break;
 			}
 
@@ -187,60 +187,38 @@ public class ExcelService {
 			excelWriter.finish();
 		}
 
-		params.setCount(total);
+		log.info("export count total is :" + exportedCountTotal);
+		params.setCount(exportedCountTotal);
 		return isSuccess;
 	}
 
+
 	/**
-	 * 动态生成表头
+	 * 结果导出到excel文件中
+	 * 
+	 * @param desens      手机号是否脱敏
+	 * @param excelWriter excel写入器
+	 * @param columnList  字段
+	 * @param tagList     结果
+	 * @param groupName   人群名称
+	 * 
+	 * @return 本次写入的去重后的手机号数量
 	 */
-	private List<List<String>> buidlHeader(List<TagColumn> columnList) {
-		List<List<String>> list = new ArrayList<List<String>>();
-
-		List<String> headPhone = new ArrayList<String>();
-		headPhone.add("手机号");
-		list.add(headPhone);
-
-		List<String> headMonth = new ArrayList<String>();
-		headMonth.add("月份");
-		list.add(headMonth);
-
-		columnList.forEach(col -> {
-			List<String> head = new ArrayList<String>();
-			head.add(col.cnName);
-			list.add(head);
-		});
-		return list;
-	}
-
-	private List<TagColumn> getFieldList(List<String> codeList) {
-		List<TagColumn> list = new ArrayList<>();
-		if (codeList != null && !codeList.isEmpty()) {
-			codeList.forEach(code -> {
-				TagColumn weiduColumn = userProfileService.getColumNameExport(code);
-				if (weiduColumn != null && weiduColumn.columnC != null
-						&& !weiduColumn.columnC.contains("EVENT_UNSPNAME")) {
-					// 该字段会严重影响查询速度,暂时屏蔽掉
-					list.add(weiduColumn);
-				}
-			});
-		}
-		return list;
-	}
-
-	private void excel(boolean desens, ExcelWriter excelWriter, List<TagColumn> columnList,
+	private int excel(ConcurrentHashMap<String, String> mobileMap, boolean desens, ExcelWriter excelWriter,
+			List<TagColumn> columnList,
 			List<Map<String, Object>> tagList, String groupName) {
+		int count = 0;
 		groupName = StringUtils.isNotBlank(groupName) ? groupName : "1";
 		List<List<Object>> list = new ArrayList<List<Object>>();
-		Map<String, Object> mobileMap = new HashMap<>();
-		tagList.forEach(tag -> {
+		for (Map<String, Object> tag : tagList) {
 			List<Object> data = new ArrayList<Object>();
 			/** ---------去重手机号------ **/
 			String mobile = tag.get("USERID_V").toString();
-			if(mobileMap.containsKey(mobile)) {
-				return;
+			if (mobileMap.containsKey(mobile)) {
+				continue;
 			}
-			mobileMap.put(mobile, new Object());
+			mobileMap.put(mobile, mobile);
+			count += 1;
 			/** ---------去重手机号------ **/
 			if (desens) {
 				// 手机号脱敏
@@ -280,8 +258,46 @@ public class ExcelService {
 			});
 
 			list.add(data);
-		});
+		}
 
 		excelWriter.write(list, EasyExcel.writerSheet(groupName).build());
+		return count;
+	}
+	
+	/**
+	 * 动态生成表头
+	 */
+	private List<List<String>> buidlHeader(List<TagColumn> columnList) {
+		List<List<String>> list = new ArrayList<List<String>>();
+
+		List<String> headPhone = new ArrayList<String>();
+		headPhone.add("手机号");
+		list.add(headPhone);
+
+		List<String> headMonth = new ArrayList<String>();
+		headMonth.add("月份");
+		list.add(headMonth);
+
+		columnList.forEach(col -> {
+			List<String> head = new ArrayList<String>();
+			head.add(col.cnName);
+			list.add(head);
+		});
+		return list;
+	}
+
+	private List<TagColumn> getFieldList(List<String> codeList) {
+		List<TagColumn> list = new ArrayList<>();
+		if (codeList != null && !codeList.isEmpty()) {
+			codeList.forEach(code -> {
+				TagColumn weiduColumn = userProfileService.getColumNameExport(code);
+				if (weiduColumn != null && weiduColumn.columnC != null
+						&& !weiduColumn.columnC.contains("EVENT_UNSPNAME")) {
+					// 该字段会严重影响查询速度,暂时屏蔽掉
+					list.add(weiduColumn);
+				}
+			});
+		}
+		return list;
 	}
 }