sql查询根据与用户的接近度来投放广告

Posted

技术标签:

【中文标题】sql查询根据与用户的接近度来投放广告【英文标题】:sql query to serve ads based on proximity to user 【发布时间】:2018-10-29 12:05:06 【问题描述】:

好的,我正在我的网站上实施广告系统。我目前根据他们在注册时输入的城市存储会员的纬度/经度坐标。每个广告都可以选择提供地理坐标并以英里为单位指定半径(尽管我也希望以公里为单位指定一个选项)。

Sample tables
--------------users
user_id = 7
name = Charles
lat = xxxxxx.xx
lon = xxxxxx.xx

--------------ads
ad_id = 1121
advertiser_id = 42
ad_type = 728x90
proximity = 50
lat = xxxxxx.xx
lon = xxxxxx.xx

我有这段代码可以搜索我的用户数据库并返回指定距离内的用户。我想我可以对其进行编辑,使其适合我的需要。但是,我不想显示指定距离内的所有用户,而是显示广告本身指定的距离内的广告,因为一个广告客户可能指定与另一个广告客户不同的接近度,等等。

这是我使用的原始用户邻近查询:

SELECT users.user_id
     , ( 3959 * acos( cos( radians('".$lat."') ) * 
                      cos( radians( users.lat ) ) * 
                      cos( radians( users.lng ) - 
                           radians('".$lng."') ) + 
                      sin( radians('".$lat."') ) * 
                      sin( radians( users.lat ) ) 
                    ) ) AS distance 
  FROM users 
 WHERE account_type = '1' 
   AND `active` = '1' 
HAVING distance <= '".$dist."'"

所以我想如果我可能首先创建一个查询以获取与该区域匹配并具有邻近要求的广告,然后选择它们的纬度/经度并选择当前用户的地理坐标,然后......我可以似乎没有把我的头绕在这上面。然后,我将根据每个与区域匹配的广告的不同邻近度设置执行几次计算。如果一个广告想要向 100 英里范围内的人展示,那么计算将不同于希望他的广告只向 20 英里范围内的人展示的人。可能有一种更简单的方法可以做到这一点。这会是查询构建器应用可以帮助创建的东西吗?

也许是这样的?

SELECT ads.ad_id
     , ( 3959 * acos( cos( radians('".$user_lat."') ) * 
                      cos( radians( ads.lat ) ) * 
                      cos( radians( ads.lng ) - 
                           radians('".$user_lng."') ) + 
                      sin( radians('".$user_lat."') ) * 
                      sin( radians( ads.lat ) ) 
                    )) AS distance 
  FROM ads 
 WHERE ad_type = '728x90' 
   AND `active` = '1' 
HAVING distance <= ads.proximity"

【问题讨论】:

见:Why should I provide an MCVE for what seems to me to be a very simple SQL query? 另外,Charles 住在一个城市,所以我希望看到一个单独的城市表,以及它们各自的坐标(可能还有近似半径) 运行大量互联网用户的昂贵 SQL 无论如何都在运行广告拦截器.. @RaymondNijland 是的,但是这个解决方案可以满足我所有的广告服务需求,包括横幅、块、html 广告、iframe 和视频广告。我不认为广告拦截器会阻止所有这些视频广告,尽管我可能弄错了。感谢大家的意见。让它按要求工作。 【参考方案1】:

我想出的最终查询解决方案是这样的:

SELECT ads.ad_id
     , proximity AS P, ( 3959 * acos( cos( radians('".$usr_lat."') ) * 
                                      cos( radians( ads.lat ) ) * 
                                      cos( radians( ads.lon ) - 
                                           radians('".$usr_lon."') ) + 
                                      sin( radians('".$usr_lat."') ) * 
                                      sin( radians( ads.lat ) ) 
                                    ) ) AS distance 
FROM ads 
WHERE ads.type = '728x90' 
AND ads.active = '1' 
HAVING distance <= P 
OR P='0' 
ORDER BY distance ASC

我添加了 OR P='0' 来投放未指定邻近度的广告。

【讨论】:

【参考方案2】:

您还可以进一步限制在进行所有数学运算之前必须计算的数据量。

当您将纬度/经度值限制为附近的值时,您可以限制必须计算距离的数据范围。 (公式来了from these slides (page 12ff)这在您按英里计算时有效......否则您必须使用正确的公里值调整“69”。

1° of latitude ~= 69 miles 
1° of longitude ~= cos(latitude)*69

当您想计算较小矩形的经度和纬度时,可以使用(使用上面的变量):

$lon1 = $lon - $dist / abs(cos(deg2rad($lat))*69);
$lon2 = $lon + $dist / abs(cos(deg2rad($lat))*69);
$lat1 = $lat - ($dist / 69);
$lat2 = $lat + ($dist / 69);

然后你像这样修改你的查询:

SELECT ads.ad_id
     , proximity AS P, ( 3959 * acos( cos( radians('".$usr_lat."') ) * 
                                      cos( radians( ads.lat ) ) * 
                                      cos( radians( ads.lon ) - 
                                           radians('".$usr_lon."') ) + 
                                      sin( radians('".$usr_lat."') ) * 
                                      sin( radians( ads.lat ) ) 
                                    ) ) AS distance 
FROM ads 
WHERE ads.type = '728x90' 
AND ads.active = '1' 
AND ads.lon BETWEEN $lon1 AND $lon2 
AND ads.lat BETWEEN $lat1 AND $lat2
HAVING distance <= P 
OR P='0' 
ORDER BY distance ASC

这应该会大大提高整体速度,因为您只使用所有坐标的一个子集。

另外一点:如果您将 lat/lon/distance 作为数字字段,则不应在值周围使用 '',因为这会触发隐式转换,这也可能需要一些时间...

【讨论】:

以上是关于sql查询根据与用户的接近度来投放广告的主要内容,如果未能解决你的问题,请参考以下文章

使用 2GB+ 加速单个表上的 SQL 查询

什么是百度信息流广告,想要投放找谁?

今日头条信息流投放与用户属性分析

SQL查询最接近某一值的数据

根据用户输入查询 SQL 表以返回同一行的值

根据时间范围对用户活动进行分组的 SQL 查询