PHP项目同城筛选如何根据城市分组数据查询

wen PHP项目 23

本文目录导读:

PHP项目同城筛选如何根据城市分组数据查询

  1. 方案一:MySQL原生分组查询(推荐)
  2. 方案二:使用Redis进行缓存分组
  3. 方案三:Elasticsearch搜索引擎(大数据量推荐)
  4. 前端展示示例
  5. 性能优化建议
  6. 选择建议

在PHP项目中实现同城筛选,推荐使用数据库分组查询(GROUP BY) + 城市索引优化的方式,以下是几种常见实现方案:

MySQL原生分组查询(推荐)

数据库表结构

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `city` varchar(20) DEFAULT NULL,  -- 城市名称
  `city_code` varchar(10) DEFAULT NULL, -- 城市编码,可选
  `province` varchar(20) DEFAULT NULL,
  `longitude` decimal(10,7) DEFAULT NULL,
  `latitude` decimal(10,7) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_city` (`city`)  -- 城市索引
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

按城市分组查询数据

// 获取所有城市及其数据数量
$sql = "SELECT city, COUNT(*) as count 
        FROM users 
        GROUP BY city 
        ORDER BY count DESC";
$result = $db->query($sql);
$cityGroups = [];
while ($row = $result->fetch_assoc()) {
    $cityGroups[] = $row;
}

查询指定城市的详细数据

// 获取某城市的详细数据
$city = $_GET['city'] ?? ''; // 前端传递的城市参数
$sql = "SELECT * FROM users WHERE city = ?";
$stmt = $db->prepare($sql);
$stmt->bind_param('s', $city);
$stmt->execute();
$result = $stmt->get_result();
$users = $result->fetch_all(MYSQLI_ASSOC);

使用Redis进行缓存分组

缓存城市分组数据

// 缓存城市分组数据
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 获取城市分组数据(缓存24小时)
$cityGroups = $redis->get('city_groups');
if (!$cityGroups) {
    // 从数据库获取
    $sql = "SELECT city, COUNT(*) as count 
            FROM users 
            GROUP BY city";
    $result = $db->query($sql);
    $cityGroups = $result->fetch_all(MYSQLI_ASSOC);
    // 缓存到Redis
    $redis->setex('city_groups', 86400, json_encode($cityGroups));
} else {
    $cityGroups = json_decode($cityGroups, true);
}

按城市存储用户ID

// 插入数据时同时维护城市分组
function insertUser($data) {
    global $db, $redis;
    // 插入数据库
    $sql = "INSERT INTO users (name, city) VALUES (?, ?)";
    $stmt = $db->prepare($sql);
    $stmt->bind_param('ss', $data['name'], $data['city']);
    $stmt->execute();
    $userId = $db->insert_id;
    // 更新Redis城市分组
    $redis->sAdd("city:{$data['city']}", $userId);
    $redis->expire("city:{$data['city']}", 86400);
    return $userId;
}
// 查询某城市用户
function getUsersByCity($city) {
    global $db, $redis;
    // 从Redis获取用户ID列表
    $userIds = $redis->sMembers("city:{$city}");
    if (!empty($userIds)) {
        $ids = implode(',', $userIds);
        $sql = "SELECT * FROM users WHERE id IN ($ids)";
        $result = $db->query($sql);
        return $result->fetch_all(MYSQLI_ASSOC);
    }
    return [];
}

Elasticsearch搜索引擎(大数据量推荐)

安装Elasticsearch-PHP客户端

composer require elasticsearch/elasticsearch

索引数据

use Elasticsearch\ClientBuilder;
$client = ClientBuilder::create()->build();
// 批量索引数据
$params = ['body' => []];
foreach ($users as $user) {
    $params['body'][] = [
        'index' => [
            '_index' => 'users',
            '_id'    => $user['id']
        ]
    ];
    $params['body'][] = [
        'name' => $user['name'],
        'city' => $user['city'],
        'province' => $user['province']
    ];
}
$responses = $client->bulk($params);

按城市聚合查询

// 城市分组聚合查询
$params = [
    'index' => 'users',
    'body'  => [
        'size' => 0,
        'aggs' => [
            'by_city' => [
                'terms' => [
                    'field' => 'city.keyword',
                    'size'  => 100 // 最多返回100个城市
                ]
            ]
        ]
    ]
];
$response = $client->search($params);
$buckets = $response['aggregations']['by_city']['buckets'];
foreach ($buckets as $bucket) {
    echo "城市: " . $bucket['key'] . ",数量: " . $bucket['doc_count'] . "<br>";
}
// 查询指定城市数据
$params = [
    'index' => 'users',
    'body'  => [
        'query' => [
            'term' => [
                'city.keyword' => '北京'
            ]
        ]
    ]
];
$response = $client->search($params);
$users = $response['hits']['hits'];

前端展示示例

<!-- 城市筛选下拉框 -->
<select id="citySelect" onchange="filterByCity()">
    <option value="">全部城市</option>
    <?php foreach ($cityGroups as $city): ?>
    <option value="<?php echo $city['city']; ?>">
        <?php echo $city['city'] . ' (' . $city['count'] . ')'; ?>
    </option>
    <?php endforeach; ?>
</select>
<!-- 数据列表 -->
<div id="userList">
    <?php foreach ($users as $user): ?>
    <div class="user-item">
        <span><?php echo $user['name']; ?></span>
        <span><?php echo $user['city']; ?></span>
    </div>
    <?php endforeach; ?>
</div>
<script>
function filterByCity() {
    var city = document.getElementById('citySelect').value;
    window.location.href = '?city=' + city;
}
</script>

性能优化建议

  1. 索引优化:确保city字段有索引
  2. 分页查询:使用LIMIT限制返回数据量
  3. 缓存策略:对城市分组结果设置缓存
  4. 数据分片:大数据量考虑MySQL分表或MongoDB
  5. 异步加载:使用AJAX实现无刷新筛选

选择建议

  • 数据量 < 10万:MySQL分组查询即可
  • 数据量 10万-100万:Redis缓存分组
  • 数据量 > 100万:Elasticsearch搜索引擎

抱歉,评论功能暂时关闭!