赞
踩
大型分布式的商城项目,例如京东,淘宝的关键字搜索框如何高效地检索数据?
如果使用数据库的模糊查询,像是like,缺点如下:
速度非常慢,因为LIKE是将数据从头到尾匹配,在大数据的情况下,匹配速度会非常久
需要匹配的数据库表、数据库数据众多
使用全文检索引擎:可以通过提前将数据库中要检索的数据,放入到全文搜索工具中,将所有数据按照一定的规则进行排序,再进搜索
优点:
速度快:按照一定的规则排序之后,无论用户搜索什么,我们都可以快速找到对应数据
可以实现搜索相似度高的数据排在前面
关键字的高亮,仔细观察我们的百度搜索、商城搜索,可以发现我们搜索的关键字是会有颜色标注的
只处理文本不处理语义:意思就是把相关搜索结果文章告诉你,而不是直接得到答案
全文检索引擎的优点:搜索速度快,可根据需求进行定制化配置

全文搜索领域,Lucene被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库
但是Lucene只是一个库,想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,而且Lucene的配置及使用非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的,所以我们需要使用Lucene的包装技术ElasticSearch
ES是一个分布式的全文搜索引擎,为了解决原生Lucene使用的不足,优化Lucene的调用方式,并实现了高可用的分布式集群的搜索方案,ES的索引库管理支持依然是基于Apache Lucene™的开源搜索引擎
ES使用Java开发,并使用Lucene作为其核心来实现索引创建和索引搜索的功能,但是它的目的是通过简单的 RESTful API来替换掉Lucene的复杂性,从而让全文搜索变得简单
总的来说ElasticSearch简化了全文检索lucene的使用,同时增加了分布式的特性,使得构建大规模分布式全文检索变得非常容易 ,底层基于Luence,上手快。
添加一个文档:
PUT /shop/user/1
{
"id":1,
"name":"张三"
}
根据索引获取文档:
GET /shop/user/1
分布式架构:ES是一种基于Lucene的分布式全文搜索引擎,在数据存储和查询方面具有较强的并发处理能力和水平扩展能力。例如,在日志分析领域,使用ELK Stack(Elasticsearch、Logstash和Kibana)将日志收集、过滤、存储和可视化展现的整个流程,其中的Elasticsearch作为强大的搜索引擎支持海量日志的快速检索和分析。
实时搜索:ES支持实时查询,并且可以在毫秒级别内返回搜索结果,有效地支持监控应用程序、搜索引擎、电商应用、金融交易等需要快速反馈的场景。例如,在电商应用领域,使用ES来搜索商品可以实现实时展示用户感兴趣的商品信息,提高用户购物体验。
强大的搜索功能:ES拥有先进的搜索能力,可以支持全文检索、多字段匹配、模糊匹配、拼音转换、近似搜索、词项匹配等多种搜索方式,同时还支持聚合、分组、分页、排序等高级特性。例如,在社交网络应用中,可以使用ES来搜索用户、话题和帖子,实现高效的匹配和聚合。
易于使用:ES提供了简单易用的API和UI界面,支持多种编程语言的客户端,方便开发人员进行搜索和管理。同时ES还有许多插件和第三方工具,如Kibana、Beats等,能够进一步扩展ES的功能。例如,在安全分析领域,使用Elasticsearch Security插件可以扩展ES的用户认证和授权功能,提高系统的安全性。
大数据处理能力:ES支持海量数据的存储和处理,并且能够与Hadoop、Spark等大数据技术结合使用,处理大规模数据。例如,在广告推荐系统中,使用ES作为数据存储和查询的引擎,可以处理千万级别的用户和广告数据,从而实现更准确的推荐服务。
开源免费:ES是一款开源软件,采用Apache 2.0许可证,可以免费使用和修改,对于独立开发者和小型企业来说成本较低。例如,国内知名的拼音搜索引擎Pinyinjoe就采用了Elasticsearch,提供了开放的搜索接口。
综上所述,ES具有分布式、实时、强大的搜索功能、易于使用、大数据处理能力和开源免费等多种优点,成为了企业级全文搜索引擎的首选方案,被广泛应用于多个领域。









# 创建索引,可以先删除索引,再重新添加文档类型映射 DELETE shop PUT /shop PUT /shop/_doc/_mapping { "_doc":{ "properties": { "id":{ "type": "long" }, "name":{ "type": "text", "analyzer": "ik_smart", "search_analyzer": "ik_smart" }, "age":{ "type": "integer" }, "sex":{ "type": "integer" } } } } GET /shop/_doc/_search GET /shop/_doc/_search { "query":{ "bool":{ "must": [{ "match": { "name":"我在成都" } } ], "filter": [{ "term": { "sex": { "value": "1" } } },{ "range": { "age": { "gte": 1, "lte": 12 } } } ] } }, "from": 2, "size":2, "sort": [ { "age": "desc" } ], "_source": ["name","age","sex"] }
package com.alibaba.es; import com.alibaba.utils.ESClientUtil; import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.sort.SortOrder; import org.junit.Test; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.stream.Stream; public class EsTest { /* * ES的crud * */ @Test public void testAdd() { TransportClient client = ESClientUtil.getClient();// 获取连接,这里的client就是java连接ES的客户端 // 添加数据 // client.prepareIndex("索引名","类型名","id").setSource("json格式的数据").get(); IndexRequestBuilder indexRequestBuilder = client.prepareIndex("shop", "_doc"); Map<String, Object> map = new HashMap<>(); map.put("id", 2); map.put("name", "李思思"); map.put("age", 16); map.put("sex", 0); IndexResponse indexResponse = indexRequestBuilder.setSource(map).get(); System.out.println(indexResponse); } @Test public void testGet() { TransportClient client = ESClientUtil.getClient();// 获取连接,这里的client就是java连接ES的客户端 // 查询数据 // client.prepareGet("索引名","类型名","id").get(); // client.prepareGet("索引名","类型名","id").setOperationThreaded(false).get(); GetResponse documentFields = client.prepareGet("shop", "_doc", "9g4_vogBBfk9FP3Z9OLv").get(); System.out.println(documentFields.getSourceAsString()); } @Test public void testUpdate() { TransportClient client = ESClientUtil.getClient();// 获取连接,这里的client就是java连接ES的客户端 // 修改数据 // client.prepareUpdate("索引名","类型名","id").setDoc("json格式的数据").get(); IndexRequestBuilder indexRequestBuilder = client.prepareIndex("shop", "_doc", "9g4_vogBBfk9FP3Z9OLv"); Map<String, Object> map = new HashMap<>(); map.put("name", "李二麻子"); IndexResponse indexResponse = indexRequestBuilder.setSource(map).get(); System.out.println(indexResponse); } @Test public void testDelete() { TransportClient client = ESClientUtil.getClient();// 获取连接,这里的client就是java连接ES的客户端 // 删除数据 // client.prepareDelete("索引名","类型名","id").get(); DeleteResponse deleteResponse = client.prepareDelete("shop", "_doc", "9g4_vogBBfk9FP3Z9OLv").get(); System.out.println(deleteResponse); } /* 复杂查询 条件 - 查询_doc表 - name包含:我在成都 - age在1~12之间 - sex=1 - 每页大小2 - 从2页开始查 - 按照age倒序 */ @Test public void testQuery() { TransportClient client = ESClientUtil.getClient();// 获取连接,这里的client就是java连接ES的客户端 // 复杂查询 // client.prepareSearch("索引名").setTypes("类型名").setQuery(QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("字段名","字段值"))).get(); SearchRequestBuilder searchRequestBuilder = client.prepareSearch("shop").setTypes("_doc"); // 查询_doc表 // 查询条件 // 查询_doc表 // - name包含:我在成都 // - age在1~12之间 // - sex=1 // - 每页大小2 // - 从2页开始查 // 按照age倒序 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); // 分页查询 searchRequestBuilder.setFrom(2).setSize(2); // 排序, 按照age倒序 searchRequestBuilder.addSort("age", SortOrder.DESC); // name包含:我在成都 boolQueryBuilder.must(QueryBuilders.matchQuery("name", "我在成都")); // sex = 1, age在1~12之间 boolQueryBuilder.filter(QueryBuilders.termQuery("sex", 1)).filter(QueryBuilders.rangeQuery("age").gte(1).lte(12)); // 查询 SearchRequestBuilder searchRequestBuilder1 = searchRequestBuilder.setQuery(boolQueryBuilder); // 将结果转换为map输出 Stream<SearchHit> stream = Arrays.stream(searchRequestBuilder1.get().getHits().getHits()); // 流转换为数组 SearchHit[] searchHits = stream.toArray(SearchHit[]::new); System.out.println(Arrays.toString(searchHits)); // System.out.println(searchRequestBuilder1.get().getHits().getHits()); } @Test public void testGenData(){ TransportClient client = ESClientUtil.getClient(); // for循环生成数据 IndexRequestBuilder indexRequestBuilder = client.prepareIndex("shop", "_doc"); Map<String, Object> map = new HashMap<>(); for (int i = 0; i < 100; i++) { map.put("id", i); map.put("name", i%2==0?"李思思"+i:"我在成都"); map.put("age", i); map.put("sex", i%2==0?0:1); indexRequestBuilder.setSource(map).get(); // 清空map数据 map.clear(); } } }
{ "took" : 20, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 6, "max_score" : null, "hits" : [ { "_index" : "shop", "_type" : "_doc", "_id" : "_g5KvogBBfk9FP3Zo-JB", "_score" : null, "_source" : { "sex" : 1, "name" : "我在成都", "age" : 7 }, "sort" : [ 7 ] }, { "_index" : "shop", "_type" : "_doc", "_id" : "_A5KvogBBfk9FP3Zo-I2", "_score" : null, "_source" : { "sex" : 1, "name" : "我在成都", "age" : 5 }, "sort" : [ 5 ] } ] } }
这个信息是Elasticsearch查询操作的返回结果,主要包括以下几个部分: took:该查询操作耗时,单位为毫秒。 timed_out:查询操作是否超时。 _shards:查询操作在集群中涉及到的分片信息,包括: a) total:涉及到的总分片数。 b) successful:查询成功的分片数。 c) skipped:跳过的分片数。 d) failed:查询失败的分片数。 hits:查询结果,包括: a) total:符合查询条件的文档数量。 b) max_score:最高得分。 c) hits:命中的文档详细信息,包括该文档所在的索引、类型、ID等信息。 - _index:文档所在的索引名称。 - _type:文档类型。 - _id:文档ID。 - _score:文档得分。 - _source:文档内容。 - sort:排序方式和依据。 例如,上述结果中返回的6个命中文档,其中两个文档的相关信息包含有 “sex”、“name”、“age”三个字段。同时使用对“age”字段进行排序,第一个文档的“age”字段值为7,第二个文档的“age”字段值为5。
| Relational DB | ElasticSearch |
|---|---|
| 数据库 | 索引-Index |
| 表 | 类型-Type |
| 行 | 文档-Document |
| 字段 | 字段-fieId |
| SQL语句 | DSL语句 |
| 主键ID | 文档ID |

喜欢的话请给我点个赞再走吧,你的鼓励是我最大的动力!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。