(1)Elasticsearch和Solr的区别
Elasticsearch和Solr都是基于Lucene的分布式搜索引擎,它们具有高效、可扩展、分布式的特点。Elasticsearch主要适用于实时搜索、分析和数据可视化,Solr主要适用于企业级搜索。
Elasticsearch在大数据存储和实时搜索方面性能更优秀,Solr在文本分析、搜索语义理解等方面性能更强。Elasticsearch默认情况下集成了近实时搜索的功能,可以在几秒钟内从文档变更时就对新文档进行索引,而Solr需要手动设置使其能够支持实时搜索。
实例:假如有100万条数据需要搜索,使用Elasticsearch进行搜索,响应时间通常在毫秒或者数秒之间。而使用Solr进行搜索,其响应时间通常在数秒或者数十秒之间。
Elasticsearch和Solr在查询语法方面有所不同。Solr支持丰富的查询语法,能够满足更多复杂的查询需求;而Elasticsearch则采用了面向文档的查询方式,让用户能够更加方便地进行查询。同时,Elasticsearch支持通过API进行搜索以及通过Kibana进行数据可视化。
实例:假如有如下文本:“The quick brown fox jumps over the lazy dog”,我们可以用Solr进行复杂查询,如 “fox OR dog” 或 “The AND fox”,而在Elasticsearch中,我们可以更加直接地查询:“fox” 或者 “dog”。
Elasticsearch是一个开源项目,拥有庞大的社区。其API和插件的文档十分丰富,能够满足几乎所有的开发和使用需求。Solr也是一个开源项目,但是相较于Elasticsearch的社区,Solr的社区相对较小,在一些新特性的实现和开发方面可能会有所落后。
实例:如果你使用Elasticsearch中遇到了问题,你可以很容易地在论坛或者社区中找到支持和帮助,而如果你在使用Solr中遇到了问题,可能需要花费更长的时间来等待社区的响应。
(2)Elasticsearch配置
(1)【解压:elasticsearch-8.4.0】
配置:
elasticsearch.yml跨域配置
http.cors.enabled: true
http.cors.allow-origin: "*"
elasticsearch.yml访问不到9200解决
xpack.security.enabled: false
运行:elasticsearch.bat
访问:192.168.3.49:9200
(2)【解压:elasticsearch-head-master】
安装:nodejs
问题解决:
1.删除C:\Users\用户\下的.npmrc文件
2.npm cache clean --force
3.npm install -g cnpm --registery=https://registery.npm.taobao.org
运行:npm install / npm run start
访问:192.168.3.49:9100
(3)【解压:kibana-8.4.0】
配置:kibana.yml配置中文
? ? ? ? ? i18n.locale: "zh-CN"
启动:kibana.bat
(4)【解压:ik分词器D:\elasticsearch-8.4.0\plugins\ik】
(5)测试入门
最小切面
GET _analyze
{
? "analyzer": "ik_smart",
? "text": "中国共产党"
}
最细力度划分
GET _analyze
{
? "analyzer": "ik_max_word",
? "text": "中国共产党"
}
(6)自定义字典
【IKAnalyzer.cfg.xml】
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">zhaoyang.dic</entry>
【zhaoyang.dic】
赵阳
赵哥
大连赵哥
(3)索引操作
(1)创建索引
ES 软件的索引可以类比为 MySQL 中表的概念,创建一个索引,类似于创建一个表
ES 不允许修改索引
# 创建索引
# PUT+索引名
PUT myindex
(2)查询指定索引
根据索引名称查询指定索引,如果查询到,会返回索引的详细信息
# 查询索引
# GET 索引名称
GET myindex
(3)查询所有索引
这里请求路径中的_cat 表示查看的意思,indices表示索引,所以整体含义就是查看当前 ES 服务器中的所有索引
# 查询索引
GET _cat/indices
(4)删除索引
删除索引
删除指定已存在的索引
# 删除索引
# DELETE+索引名称
DELETE test_inde
(4)文档操作
(1)创建文档
这里的文档可以类比为关系型数据库中的表数据,添加的数据格式为 JSON 格式
如果在创建数据时,指定唯一性标识,那么请求范式 POST,PUT 都可以
如果没有指定数据唯一性标识,只能使用 POST 请求
# 创建文档
# 创建文档
POST myindex/_doc/001
{
? "id" : 1001,
? "name" : "zhangsan",
? "age" : 30
}
POST myindex/_doc/002
{
? "id" : 1002,
? "name" : "lisi",
? "age" : 18
}
POST myindex/_doc/003
{
? "id" : 1004,
? "name" : "wangwu",
? "age" : 30
}
POST myindex/_doc/004
{
? "id" : 1004,
? "name" : "zhaoliu",
? "age" : 35
}
(2)查询文档
根据唯一性标识可以查询对应的文档
# 查询文档
GET myindex/_doc/001
(3)修改文档
修改文档本质上和新增文档是一样的,如果存在就修改,如果不存在就新增
# 修改文档
PUT myindex/_doc/001
{
? "age":20
}
(4)删除文档
删除一个文档不会立即从磁盘上移除,它只是被标记成已删除(逻辑删除)
# 删除文档
DELETE myindex/_doc/001
(5)查询所有文档
# 查询所有文档
GET myindex/_search
(5)数据搜索
(1)匹配查询文档
这里的查询表示文档数据中 JSON 对象数据中的 name 属性是lisi
GET myindex/_search
{
? "query": {
? "match": {
? ? "name": "lisi" #不会查出li si 此时查询关键字是lisi 而li si 的关键词是两个【li】【si】匹配不上
? }
? }
}
GET myindex/_search
{
? "query": {
? ? "term": {
? ? ? "name": {
? ? ? ? "value": "li si" #会查出li si 不会查出lisi? 此时关键字是li si
? ? ? }
? ? }
? }
}
(2)匹配查询字段
默认情况下,Elasticsearch 在搜索的结果中,会把文档中保存在_source 的所有字段都返回。如果我们只想获取其中的部分字段,我们可以添加_source 的过滤
GET myindex/_search
{
? "_source": ["name","age"],
? "query": {
? ? "term": {
? ? ? "name": {
? ? ? ? "value": "lisi"
? ? ? }
? ? }
? }
}
(3)组合"or"
GET myindex/_search
{
? "_source": ["name","age"],
? "query": {
? ? "bool": {
? ? ? "should": [
? ? ? ? {
? ? ? ? ? "match": {
? ? ? ? ? ? "name": "lisi"
? ? ? ? ? }
? ? ? ? },
? ? ? ? {
? ? ? ? ? "match": {
? ? ? ? ? ? "age": 35
? ? ? ? ? }
? ? ? ? }
? ? ? ]
? ? }
? }
}
(4)排序
GET myindex/_search
{
? "query": {
? ? "match_all": {}
? },
? "sort": [
? ? {
? ? ? "age": {
? ? ? ? "order": "desc"
? ? ? }
? ? }
? ]
}
(5)分页
GET myindex/_search
{
? "query": {
? ? "match_all": {}
? },
? "from": 0,
? "size": 2
}
(6)分组
GET myindex/_search
{
"aggs": {
? "ageGroup": {
? ? "terms": {
? ? ? "field": "age"
? ? }
? }
},
"size": 0 #只显示分组信息 不显示源信息
}
(7)平均值
GET myindex/_search
{
"aggs": {
? "ageAvg": {
? ? "avg": {
? ? ? "field": "age"
? ? }
? }
},
"size": 0
}
(8)求和
GET myindex/_search
{
"aggs": {
? "ageGroup": {
? ? "terms": {
? ? ? "field": "age"
? ? },
? ? "aggs": {
? ? ? "ageSum": {
? ? ? ? "sum": {
? ? ? ? ? "field": "age"
? ? ? ? }
? ? ? }
? ? }
? }
},
"size": 0
}
(9)TopN
GET myindex/_search
{
"aggs": {
? "Top3": {
? ? "top_hits": {
? ? ? "sort": [
? ? ? ? {
? ? ? ? ? "age": {
? ? ? ? ? ? "order": "desc"
? ? ? ? ? }
? ? ? ? }
? ? ? ? ],
? ? ? "size": 3
? ? }
? }
},
"size": 0
}
(6)SpringBoot+Elasticsearch
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>co.elastic.clients</groupId>
? ? ? ? ? ? <artifactId>elasticsearch-java</artifactId>
? ? ? ? ? ? <version>8.1.0</version>
? ? ? ? </dependency>
@Configuration
public class ElasticSearchConfig {
? ? @Bean
? ? public ElasticsearchClient elasticsearchClient(){
? ? ? ? RestClient client = RestClient.builder(new HttpHost("localhost", 9200,"http")).build();
? ? ? ? ElasticsearchTransport transport = new RestClientTransport(client,new JacksonJsonpMapper());
? ? ? ? return new ElasticsearchClient(transport);
? ? }
}
/**
*
* springBoot整合ElasticSearch8.x版本
*
*/
@SpringBootTest
class EsApplicationTests {
? ? @Autowired
? ? private ElasticsearchClient client;
? ? // 索引 CRUD
? ? // (1)增加index
? ? @Test
? ? public void createTest() throws IOException {
? ? ? ? CreateIndexResponse indexResponse = client.indices().create(c -> c.index("user"));
? ? }
? ? // (2)查询Index
? ? @Test
? ? public void queryTest() throws IOException {
? ? ? ? GetIndexResponse getIndexResponse = client.indices().get(i -> i.index("user"));
? ? }
? ? // (3)判断index是否存在
? ? @Test
? ? public void existsTest() throws IOException {
? ? ? ? BooleanResponse booleanResponse = client.indices().exists(e -> e.index("user"));
? ? ? ? System.out.println(booleanResponse.value());
? ? }
? ? // (4)删除index
? ? @Test
? ? public void deleteTest() throws IOException {
? ? ? ? DeleteIndexResponse deleteIndexResponse = client.indices().delete(d -> d.index("user"));
? ? ? ? System.out.println(deleteIndexResponse.acknowledged());
? ? }
? ? // Document CRUD
? ? // (1)插入document
? ? @Test
? ? public void addDocumentTest() throws IOException {
? ? ? ? User user = new User("user1", 10);
? ? ? ? IndexResponse indexResponse = client.index(i -> i
? ? ? ? ? ? ? ? .index("user")
? ? ? ? ? ? ? ? //设置id
? ? ? ? ? ? ? ? .id("1")
? ? ? ? ? ? ? ? //传入user对象
? ? ? ? ? ? ? ? .document(user));
? ? }
? ? // (2)更新Document
? ? @Test
? ? public void updateDocumentTest() throws IOException {
? ? ? ? UpdateResponse<User> updateResponse = client.update(u -> u
? ? ? ? ? ? ? ? ? ? ? ? .index("user")
? ? ? ? ? ? ? ? ? ? ? ? .id("1")
? ? ? ? ? ? ? ? ? ? ? ? .doc(new User("user2", 13))
? ? ? ? ? ? ? ? , User.class);
? ? }
? ? // (3)判断Document是否存在
? ? @Test
? ? public void existDocumentTest() throws IOException {
? ? ? ? BooleanResponse indexResponse = client.exists(e -> e.index("user").id("1"));
? ? ? ? System.out.println(indexResponse.value());
? ? }
? ? // (4)查询Document
? ? @Test
? ? public void getDocumentTest() throws IOException {
? ? ? ? GetResponse<User> getResponse = client.get(g -> g
? ? ? ? ? ? ? ? ? ? ? ? .index("user")
? ? ? ? ? ? ? ? ? ? ? ? .id("1")
? ? ? ? ? ? ? ? , User.class
? ? ? ? );
? ? ? ? System.out.println(getResponse.source());
? ? }
? ? // (5)删除Document
? ? @Test
? ? public void deleteDocumentTest() throws IOException {
? ? ? ? DeleteResponse deleteResponse = client.delete(d -> d
? ? ? ? ? ? ? ? .index("user")
? ? ? ? ? ? ? ? .id("1")
? ? ? ? );
? ? ? ? System.out.println(deleteResponse.id());
? ? }
? ? // (6)批量插入Document
? ? @Test
? ? public void bulkTest() throws IOException {
? ? ? ? List<User> userList = new ArrayList<>();
? ? ? ? userList.add(new User("user1", 11));
? ? ? ? userList.add(new User("user2", 12));
? ? ? ? userList.add(new User("user3", 13));
? ? ? ? userList.add(new User("user4", 14));
? ? ? ? userList.add(new User("user5", 15));
? ? ? ? List<BulkOperation> bulkOperationArrayList = new ArrayList<>();
? ? ? ? //遍历添加到bulk中
? ? ? ? for(User user : userList){
? ? ? ? ? ? bulkOperationArrayList.add(BulkOperation.of(o->o.index(i->i.document(user))));
? ? ? ? }
? ? ? ? BulkResponse bulkResponse = client.bulk(b -> b.index("user")
? ? ? ? ? ? ? ? .operations(bulkOperationArrayList));
? ? }
? ? // (7)查询
? ? @Test
? ? public void searchTest() throws IOException {
? ? ? ? SearchResponse<User> search = client.search(s -> s
? ? ? ? ? ? ? ? .index("user")
? ? ? ? ? ? ? ? //查询name字段包含hello的document(不使用分词器精确查找)
? ? ? ? ? ? ? ? .query(q -> q
? ? ? ? ? ? ? ? ? ? ? ? .term(t -> t
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .field("name")
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .value(v -> v.stringValue("hello"))
? ? ? ? ? ? ? ? ? ? ? ? ))
? ? ? ? ? ? ? ? //分页查询,从第0页开始查询3个document
? ? ? ? ? ? ? ? .from(0)
? ? ? ? ? ? ? ? .size(3)
? ? ? ? ? ? ? ? //按age降序排序
? ? ? ? ? ? ? ? .sort(f->f.field(o->o.field("age").order(SortOrder.Desc))),User.class
? ? ? ? );
? ? ? ? for (Hit<User> hit : search.hits().hits()) {
? ? ? ? ? ? System.out.println(hit.source());
? ? ? ? }
? ? }
}