Elasticsearch实战指南:让你的业务搜索飞起来

当你的MySQL数据库查询突然从0.5秒飙升到15秒,当你的产品经理第20次提出"模糊搜索要支持同义词联想"时——是时候重新认识这个改变搜索游戏规则的分布式搜索引擎了。

1.为什么Elasticsearch是新时代的“数据引擎”?

传统数据库的三大死穴

模糊查询性能差(LIKE耗时随数据量指数级上升)缺乏智能排序(无法根据用户行为动态加权)扩展性弱(分库分表成本高)

ES的破局武器

分布式架构:线性扩展支撑 PB 级数据倒排索引:毫秒级响应关键词搜索分词引擎:中文/拼音/同义词精准匹配

2.五大场景+完整代码:从入门到实战

电商搜索——让用户“一搜即中”痛点用户搜索“苹果手机”时,无法智能匹配“iPhone”搜索结果排序僵化(无法综合销量/评分/价格动态排序)代码实现
复制
// 商品实体类 @Document(indexName = "products") public class Product { @Id private String id; // 使用ik_max_word分词器 @Field(type = FieldType.Text, analyzer = "ik_max_word") private String title; private Double price; private Long sales; // getters/setters } // 搜索服务 @Service public class ProductService { @Autowired private ElasticsearchOperations esOperations; public List<Product> search(String keyword) { Query query = NativeQuery.builder() .withQuery(q -> q .match(m -> m // 多字段匹配 .field("title") .field("description") .query(keyword) ) ) .withSort(s -> s // 综合排序:销量倒序 > 价格升序 .field(f -> f.field("sales").order(SortOrder.Desc)) .field(f -> f.field("price").order(SortOrder.Asc)) ) .build(); return esOperations.search(query, Product.class) .stream().map(SearchHit::getContent).collect(Collectors.toList()); } }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.
推荐系统——让用户“欲罢不能”痛点用户兴趣变化快,推荐结果更新延迟高无法实时结合用户位置/行为调整策略代码实现
复制
// 用户画像实体 @Document(indexName = "user_profiles") public class UserProfile { @Field(type = FieldType.Keyword) private String userId; // 用户兴趣标签(可动态更新) @Field(type = FieldType.Keyword) private List<String> tags; @GeoPointField private GeoPoint lastLocation; } // 附近相似用户推荐 public List<UserProfile> recommendUsers(String userId, int radiusKm) { UserProfile current = getUserById(userId); // 获取当前用户 Query query = NativeQuery.builder() .withQuery(q -> q .bool(b -> b .must(m -> m.geoDistance(g -> g // 地理过滤 .field("lastLocation") .distance(radiusKm + "km") .location(l -> l.latlon(ll -> ll.lat(current.getLastLocation().lat()) .lon(current.getLastLocation().lon()) )) )) .must(m -> m.terms(t -> t // 标签匹配 .field("tags") .terms(t2 -> t2.value(current.getTags())) ) ) ) .build(); return esOperations.search(query, UserProfile.class) .stream().map(SearchHit::getContent) .collect(Collectors.toList()); }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.
地理搜索——让“附近的人”触手可及痛点MySQL地理计算性能差(ST_Distance函数消耗大)无法支持复杂地理围栏完整实现
复制
// 商家实体(含地理位置) @Document(indexName = "shops") public class Shop { @Id private String id; @GeoPointField // 关键注解! private GeoPoint location; @Field(type = FieldType.Text) private String name; } // 附近商家服务 @Service public class ShopService { public List<Shop> findNearby(double lat, double lon, double radiusKm) { Query query = NativeQuery.builder() .withQuery(q -> q .geoDistance(g -> g .field("location") .distance(radiusKm + "km") .location(gl -> gl.latlon(l -> l.lat(lat).lon(lon))) ) .withSort(s -> s // 按距离排序 .geoDistance(g -> g .field("location") .location(l -> l.latlon(ll -> ll.lat(lat).lon(lon)) .order(SortOrder.Asc)) ) .build(); return esOperations.search(query, Shop.class) .stream().map(SearchHit::getContent) .collect(Collectors.toList()); } } // 接口调用示例 @RestController @RequestMapping("/shops") public class ShopController { @GetMapping("/nearby") public List<Shop> getNearby( @RequestParam double lat, @RequestParam double lon, @RequestParam(defaultValue = "3") double radius) { return shopService.findNearby(lat, lon, radius); } }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.

3.性能对比:ES如何碾压传统方案

场景

数据量

MySQL耗时

ES耗时

优势倍数

商品搜索

1000万

4.2s

28ms

150x

附近商家查询

50万

920ms

15ms

61x

4.避坑指南:ES不是银弹

事务场景:订单支付等需强一致性时,仍需结合MySQL

冷数据存储:历史归档数据建议转存至OSS

精确统计:UV去重请用HyperLogLog

5.小结

从电商搜索到地理围栏,Elasticsearch 正在重新定义数据处理的边界。当你的业务面临以下挑战时,就是时候考虑 ES 了

数据量超过千万级需要复杂搜索/聚合对实时性要求高

阅读剩余
THE END