(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.0pluginsik】
(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());
}
}
}