首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >房产中介小程序:房源库、地图找房与多源房源去重

房产中介小程序:房源库、地图找房与多源房源去重

原创
作者头像
用户3066938
发布于 2026-10-22 16:29:08
发布于 2026-10-22 16:29:08
220
举报

房产中介小程序的功能清单不长:房源列表、地图找房、房源详情、预约看房、经纪人联系。真正难的是底下的数据问题——同一个小区、同一套房,被三个经纪人各发了一遍,用户看到重复房源,体验直接崩。

本文围绕房源建模、地图找房、去重、带看预约四条线展开。示例基于 MySQL 8 + Redis GEO。

一、房源建模:楼盘和房源要分开

房产数据天然是两层:楼盘(小区) 和 房源(具体一套)。把两者合成一张表,会重复存储小区的位置、配套、物业信息,而且小区信息一改就要批量更新。

代码语言:txt
复制
-- 楼盘/小区
CREATE TABLE community (
 id            BIGINT PRIMARY KEY AUTO_INCREMENT,
 name          VARCHAR(100) NOT NULL,
 district      VARCHAR(40) NOT NULL COMMENT '行政区',
 address       VARCHAR(200) NOT NULL,
 lat           DECIMAL(10,7) NOT NULL,
 lng           DECIMAL(10,7) NOT NULL,
 build_year    SMALLINT NULL,
 property_fee  DECIMAL(6,2) NULL COMMENT '物业费 元/㎡',
 developer     VARCHAR(100) NULL,
 UNIQUE KEY uk_name_district (name, district),
 KEY idx_district (district)
);

-- 房源
CREATE TABLE house (
 id             BIGINT PRIMARY KEY AUTO_INCREMENT,
 community_id   BIGINT NOT NULL,
 agent_id       BIGINT NOT NULL,
 biz_type       TINYINT NOT NULL COMMENT '1出售 2出租',
 layout         VARCHAR(20) NOT NULL COMMENT '如 3室2厅',
 room_count     TINYINT NOT NULL,
 hall_count     TINYINT NOT NULL,
 area           DECIMAL(7,2) NOT NULL COMMENT '建筑面积 ㎡',
 floor          SMALLINT NOT NULL,
 total_floor    SMALLINT NOT NULL,
 orientation    TINYINT NULL COMMENT '1东2南3西4北',
 decoration     TINYINT NULL COMMENT '1毛坯2简装3精装4豪装',
 price_total    INT NULL COMMENT '总价,万元(出售)',
 price_rent     INT NULL COMMENT '月租,元(出租)',
 title          VARCHAR(120) NOT NULL,
 description    TEXT NULL,
 cover_url      VARCHAR(255) NULL,
 status         TINYINT NOT NULL DEFAULT 1 COMMENT '1在售 2已成交 3已下架',
 fingerprint    CHAR(32) NOT NULL COMMENT '去重指纹',
 published_at   DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
 refreshed_at   DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
 KEY idx_comm_biz (community_id, biz_type, status),
 KEY idx_price (biz_type, price_total),
 KEY idx_agent (agent_id, status),
 KEY idx_fingerprint (fingerprint)
);

fingerprint 是解决重复房源的关键字段,下一节展开。

二、多源房源去重:指纹怎么算

中介行业有个现实:一套房源会被多个经纪人录入,甚至同一个经纪人重复录。如果不做去重,用户搜索"城西区 三居 100-150 万",会看到同一套房出现四次,价格还不一样。

去重的核心是给每套房算一个"业务指纹",让物理上同一个东西得到同一个值。

可用的字段组合是:小区 + 楼栋 + 单元 + 房号。这四个字段能唯一定位一套房。但实际数据里这些字段经常缺失或不规范("3号楼"写成"3#","1单元"写成"一单元")。

工程上的做法是做归一化,再算指纹:

代码语言:txt
复制
const crypto = require('crypto');

function normalize(s) {
 if (!s) return '';
 return String(s)
 .replace(/[##号栋幢单元座]/g, '')   // 去掉单位和符号
 .replace(/[一二三四五六七八九十]/g, c => '一二三四五六七八九十'.indexOf(c) + 1)
 .replace(/\s+/g, '')
 .toUpperCase();
}

function fingerprint(house) {
 const raw = [
 house.communityId,
 normalize(house.building),
 normalize(house.unit),
 normalize(house.roomNo),
 ].join('|');
 return crypto.createHash('md5').update(raw).digest('hex');
}

指纹不唯一时怎么办:如果楼栋房号缺失,退化为"小区 + 户型 + 面积 + 楼层"的近似指纹,置信度低,只用于提示"疑似重复",不自动合并。

合并策略要谨慎:不能简单地删掉重复的。同一套房由两个经纪人维护,其中一个可能价格更准、照片更新。合理的做法是保留一条"主房源",其他作为"同房源报价"挂在下面,详情页展示"3 位经纪人发布,最低报价 148 万"。这样既消除了重复感,又保留了竞争信息——这也是用户真正想要的。

代码语言:txt
复制
CREATE TABLE house_duplicate (
 id            BIGINT PRIMARY KEY AUTO_INCREMENT,
 master_id     BIGINT NOT NULL COMMENT '主房源',
 duplicate_id  BIGINT NOT NULL COMMENT '被合并的房源',
 confidence    TINYINT NOT NULL COMMENT '1高 2中 3低',
 created_at    DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
 UNIQUE KEY uk_dup (duplicate_id),
 KEY idx_master (master_id)
);

uk_dup 保证一套房只能被合并一次,避免形成链条(A 合并到 B,B 又合并到 C)。

三、地图找房:聚合比精度更重要

地图找房是房产小程序的标配,也是最容易做卡的功能。用户在地图上缩放,视野内可能有几千套房源,全部渲染会直接卡死。

方案:按缩放级别做网格聚合。

Redis 的 GEO 命令适合做"附近搜索",但做"视野内聚合"要自己算网格。做法是把地图按当前缩放级别切成网格,统计每个网格内的房源数和最低价:

代码语言:txt
复制
// 网格边长(度),随缩放级别变化
function gridSize(zoom) {
 const table = { 10: 0.5, 11: 0.25, 12: 0.125, 13: 0.0625, 14: 0.03125, 15: 0.015625 };
 return table[zoom] || 0.015625;
}

async function mapCluster(sw, ne, zoom, filters) {
 const size = gridSize(zoom);

 // 缩放级别足够大(比如 16+),直接返回具体房源
 if (zoom >= 16) {
 return db.query(
 `SELECT h.id, h.title, h.price_total, c.lat, c.lng
 FROM house h JOIN community c ON c.id = h.community_id
 WHERE h.status = 1 AND h.biz_type = ?
 AND c.lat BETWEEN ? AND ? AND c.lng BETWEEN ? AND ?
 LIMIT 200`,
 [filters.bizType, sw.lat, ne.lat, sw.lng, ne.lng]
 );
 }

 // 低缩放级别,按网格聚合
 return db.query(
 `SELECT
 FLOOR(c.lat / ?) AS grid_lat,
 FLOOR(c.lng / ?) AS grid_lng,
 COUNT(*) AS cnt,
 MIN(h.price_total) AS min_price,
 AVG(c.lat) AS lat,
 AVG(c.lng) AS lng
 FROM house h JOIN community c ON c.id = h.community_id
 WHERE h.status = 1 AND h.biz_type = ?
 AND c.lat BETWEEN ? AND ? AND c.lng BETWEEN ? AND ?
 GROUP BY grid_lat, grid_lng
 HAVING cnt > 0
 LIMIT 500`,
 [size, size, filters.bizType, sw.lat, ne.lat, sw.lng, ne.lng]
 );
}

LIMIT 200 / LIMIT 500 是必须的。 地图视野是不可控的——用户把地图缩到全国,视野内可能有几十万条数据。没有上限,一次请求就能把数据库拖垮。

lat/lng 存在 community 上而不是 house 上,这一点很重要:同一小区的所有房源共享坐标,避免了"同一小区的房源在地图上散成一片"的问题,也省了大量存储。

索引:community 表的 (lat, lng) 要建联合索引。MySQL 8 也支持 SPATIAL 索引配合 POINT 类型,但实测在矩形范围查询上,普通 B-Tree 联合索引配合 BETWEEN 的性能已经够用,且更容易维护。

四、带看预约:和普通预约的三点不同

房产带看预约看着像普通预约,实际有三个差异。

一是"看房"往往连带多套。 用户约一次,经纪人会安排"这条街看三套"。所以预约单要能关联多个 house_id,而不是一对一。

代码语言:txt
复制
CREATE TABLE viewing_appointment (
 id            BIGINT PRIMARY KEY AUTO_INCREMENT,
 user_id       BIGINT NOT NULL,
 agent_id      BIGINT NOT NULL,
 house_ids     JSON NOT NULL COMMENT '[123, 456, 789]',
 appoint_date  DATE NOT NULL,
 time_slot     VARCHAR(20) NOT NULL COMMENT '如 14:00-15:00',
 contact_name  VARCHAR(40) NOT NULL,
 contact_phone VARCHAR(20) NOT NULL,
 status        TINYINT NOT NULL DEFAULT 1 COMMENT '1待确认 2已确认 3已完成 4已取消 5爽约',
 remark        VARCHAR(200) NULL,
 created_at    DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
 KEY idx_agent_date (agent_id, appoint_date, status),
 KEY idx_user (user_id)
);

二是经纪人的时间要防冲突。 同一个经纪人同一时段不能接两个客户。这个校验不能用简单的唯一索引(因为时段是字符串),要在应用层加锁或者用条件更新。

三是爽约要记录。 用户约了不来,经纪人的时间就浪费了。要记录爽约次数,超过阈值(比如 3 次)限制预约,或者要求提前付小额定金。

五、房源真实性:平台最难的问题

虚假房源是房产平台的顽疾:用低价好房吸引用户,实际带看时说"这套刚卖掉,我带你看看别的"。

技术上能做的有三件事:

一是图片查重。 同一组图片被用在多个房源上,基本可以判定是虚假或重复。用感知哈希(pHash)比对,相似度超过阈值就标记。

二是价格异常检测。 同小区同户型的均价,如果某套房源低于均价 30% 以上,标记为"待核实",在列表上不优先展示,或者加提示。

三是房源有效期。 房源要定期"刷新确认",超过 N 天未确认的自动下架。这条对清理"僵尸房源"很有效——很多虚假房源是半年前发的,早就成交了。

-- 每日任务:超过 30 天未确认的房源自动下架 UPDATE house SET status = 3 WHERE status = 1 AND refreshed_at < DATE_SUB(NOW(), INTERVAL 30 DAY);

六、经纪人分佣与客户归属

中介公司的管理难点不在房源,在"这个客户算谁的"。同一个客户可能被三个经纪人先后带看,成交后佣金怎么分,是每天都在吵的事。

系统要能回答两个问题:客户第一次是谁接待的、最后一次是谁带看的。

常见规则有几种:首接保护(第一个录入客户的经纪人享有 N 天保护期)、末次带看(成交前最后一次带看的人拿主要佣金)、按带看次数分配(多人参与时按次数拆分)。

规则是业务定的,系统要做的是把过程记全:

代码语言:txt
复制
CREATE TABLE customer_visit (
 id           BIGINT PRIMARY KEY AUTO_INCREMENT,
 customer_id  BIGINT NOT NULL,
 agent_id     BIGINT NOT NULL,
 house_id     BIGINT NULL,
 visit_type   TINYINT NOT NULL COMMENT '1首次接待 2带看 3复看',
 visited_at   DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
 KEY idx_customer (customer_id, visited_at),
 KEY idx_agent (agent_id, visited_at)
);

有了这张表,无论公司采用哪种分佣规则,都能从历史记录里算出结果。反过来,如果只记"当前负责人",一旦换人,前面的贡献就查不到了,分佣只能靠回忆。

客户手机号要防私单。 经纪人私下成交、绕开公司,是行业普遍问题。技术上能做的是给客户号做虚拟中转,通话记录留痕,成交必须走系统合同。这些手段不能根治,但能提高绕过的成本。

七、小结

房产中介小程序的重点在数据层,不在界面层:

- 楼盘与房源分表,坐标挂在楼盘上,避免同小区房源散点;- 指纹去重 + 主房源合并,用"多经纪人报价"的方式保留竞争信息,而不是硬删;- 地图按缩放级别聚合,必须加 LIMIT,否则视野一放大就拖垮数据库;- 带看预约是一对多,要处理经纪人时段冲突和爽约记录;- 房源真实性 靠图片查重、价格异常、定期刷新三条防线。

青海青帝信息科技有限公司在本地房产类项目里,会把"房源去重"和"地图聚合上限"作为两个必测项——前者决定用户看到的信息质量,后者决定高峰期系统活不活。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、房源建模:楼盘和房源要分开
  • 二、多源房源去重:指纹怎么算
  • 三、地图找房:聚合比精度更重要
  • 四、带看预约:和普通预约的三点不同
  • 五、房源真实性:平台最难的问题
  • 六、经纪人分佣与客户归属
  • 七、小结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档