文本地址智能识别组件(二)

前言

前面我们提到过文本地址智能识别组件的暴力解析方式,直接如何强行匹配地址信息,但是这种方式很难维护.这次我们通过别的方式去实现地址识别的功能,达到和数据库实时同步,并且自动补全的功能,当我们地址里面输入湖南省岳麓区时自动匹配长沙市,但输入长沙市岳麓区时,自动匹配出湖南省,达到实际需求中真正的智能识别文本地址信息

方案

大概的思路是数据库中存在想对应的省市区三级甚至四级的数据,没有数据可以自行去网上下载一份导入数据库,相关的数据操作按钮功能我就不一一描述了,我们通过数据库地址的级别功能找到对应的关联关系,通过连表查询出对应的上下级地址名称,然后把相关的值传进来返回对应的地址信息再处理相关的业务,可能数据结构和业务逻辑不一样,这就需要自行处理了.

首先我们查询对应的参考数据
查询的地址结果
SQL如下

SELECT * FROM kd_region WHERE region_name = '北京市'
UNION 
SELECT * FROM kd_region WHERE region_parent_id = '110000'
UNION
SELECT * FROM kd_region WHERE region_parent_id = '110100'	

如上可看出数据库的地址表数据结构是有region_id(地址ID)和region_parent_id(父级ID),region_type(1省,2市,3区,4街道)这些关键信息所组成.

编写匹配地址业务SQL

		SELECT
		t2.province_code provinceCode,
		t2.province_name province,
		t2.city_name city,
		t2.county_name county
		FROM
		((
		SELECT
		r.region_id province_code,
		r.region_name province_name,
		r1.region_name city_name,
		r2.region_name county_name
		FROM
		kd_region r
		LEFT JOIN kd_region r1 ON r.region_id = r1.region_parent_id AND
		r1.region_type = 2 AND r1.is_del = 0
		LEFT JOIN kd_region r2 ON r1.region_id = r2.region_parent_id AND r2.is_del
		= 0
		WHERE
		r.region_type = 1 AND r.is_del= 0
		) ) t2 WHERE
		(
		INSTR('湖南省岳麓区XX路XX区',t2.province_name) 
		OR 
		INSTR('湖南省岳麓区XX路XX区',t2.city_name)
		)
		AND INSTR('湖南省岳麓区XX路XX区',t2.county_name)

通过关联地址表的父级ID查询出三级菜单,由于我们的地址有些是直辖市自治县这种特殊地址,所以关联第三级的时候我们的地址级别只要不为1或者2都可以,不然会导致部分特殊地址丢失的情况.
由于地址会自动找出丢失的第一级或者第二级,当出现重名的地址时,可以考虑随时获取识别到的地址.

具体业务处理

	/**
	 * 识别相关信息:QQ1025032391
	 * @param request
	 * @return
	 */
	@RequestMapping("/textRecognition")
	public ApiResult textRecogin(HttpServletRequest request) {
		String functionId = "/textRecognition";
		String text = request.getParameter("text");
		if (StringUtils.isEmpty(text)) {
			return error(functionId, "请传入文本信息");
		}
		String regEx = "[`~!@#$%^&*()\\-+={}':;,\\[\\].<>/?¥%…()_+|【】‘;:”“’。,、?\\s]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(text);
        text = m.replaceAll(" ");

        String[] textArr = text.split("\\s+");
        if (textArr.length != 3) {
			return error(functionId, "文本信息传入不正确");
		}
        List<String> dataList = new ArrayList<String>(Arrays.asList(textArr));
        Map<String, String> data = new HashMap<String, String> ();
        for (int i = 0; i < dataList.size(); i++) {
        	List<RegionDTO> recognition = regionService.getTextRecognition(dataList.get(i));
        	if (recognition.size() > 0) {
        		if (dataList.get(i).length() > 50) {
					return error(functionId, "地址长度不能超过50位");
				}
        		//如果多个结果,可考虑随机匹配
        		RegionDTO region = recognition.get(new Random().nextInt(recognition.size()));
        		//不随机匹配
//        		RegionDTO region = recognition.get(new Random().nextInt(recognition.size()));
        		data.put("provinceCode", region.getProvinceCode());
        		data.put("province", region.getProvince());
        		data.put("city", region.getCity());
        		data.put("county", region.getCounty());
        		String detail = dataList.get(i).replace(region.getProvince(), "").replace(region.getCity(), "").replace(region.getCounty(), "");
        		data.put("detail", detail);
        		data.put("text", Pattern.compile("\\s+").matcher(text.replace(dataList.get(i), region.getProvince()+region.getCity()+region.getCounty() + detail)).replaceAll(","));
        		dataList.remove(i);
        		break;
        	}
		}
		if (data.isEmpty() || StringUtils.isEmpty(data.get("county"))) {
			return error(functionId, "未匹配到地址信息");
		} 
		for (int i = 0; i < dataList.size(); i++) {
			if ((Pattern.compile("[0-9]*")).matcher(dataList.get(i)).matches()) {
        		if (dataList.get(i).length() > 17 || dataList.get(i).length() < 7) {
					return error(functionId, "电话号码长度为7-17位");
				}

				data.put("phone", dataList.get(i));
				dataList.remove(i);
				break;
			}
		}
		if (StringUtils.isEmpty(data.get("phone"))) {
			return error(functionId, "未识别到手机号");
		}
		if (dataList.get(0).length() > 10) {
			return error(functionId, "姓名不能超过10位");
		}
		data.put("name", dataList.get(0));
		Map tempMap = data;
		Map<String,Object> resultData = tempMap;
		return success(functionId, ApiResult.SUCCESS_MESSAGE, resultData);
	}

如上传入文本信息,就可以识别地址信息了,可能具体的业务场景不一样,可以根据自己的业务场景适当变更,但地址识别是测试过了,完全可以使用的.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章