倒排索引:根据属性值找到索引(DocID;TF) id是索引,TF是出现几次,通过词查找索引,然后在根据这个拿到的索引去找具体的位置
正派索引:根据索引找到属性值
全文搜索:
相关性:
分析:
单词搜索:搜索单个词语
多词搜索:搜索多个词语,可以使用or,and
组合搜索:包含这个条件但是不包含另外一个条件
bool评分的计算规则:
权重:人为的设置词增加权重来影响该条数据的得分->“boost”:10
短语匹配:不仅仅是词要匹配,并且词的顺序也要一致。"slop"可以设置跳过几个字
集群:
集群节点:
master节点,设置node.master属性为true,就有资格被选为master节点,作用用于控制整个集群的操作,比如创建或删错,管理其他非master节点。
date节点,用于执行数据相关的操作,比如文档的crud
客户端节点,配置文件中node.master和node.date属性均为false,用于响应用户的请求,把请求发送到data节点
部落节点,当一个节点配置了tribe.,他就是一个特殊的客户端,可以连多个集群,在所有连接的集群上执行搜索和其他操作
docker 搭建 elasticsearch集群:
1. /目录下创建es-cluseter/node01、node02
2. 复制安装目录下的jvm.options、 elasticsearch.yml 分别到node01,node02
3. 修改配置文件:
jvm.options 要将1g改成128m(看实际情况)
elasticsearch.yml配置:
discovery.zen.minimum_master_nodes: 1
http.cors.enabled: true
http.cors.allow-origin: ""
cluster.name: es-cluster
node.name: node01
network.host: 192.168.64.128
http.port: 9300
discovery.zen.ping.unicast.hosts: [“192.168.64.128”]
# 表示这个节点有资格竞选主节点
node.master: true
node.data: true
4. 设置node01,node02访问权限,因为docker启动elasticsearch不是用root用户访问,当把node01和node02和elasticsearch挂载,docker无法向node01或node02里的data文件写数据。 chmod 777 data/ -R
5.进行挂载。docker create --name es-node01 --net host -v /es-cluster/node01/elastisearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /es-cluster/node01/jvm.options:/usr/share/elasticsearch/config/jvm.options -v /es-cluster/node01/data:/usr/share/elasticsearch/data elasticsearch:6.5.4
6.启动并打印日志。 docker start es-node01 && docker logs -f es-node01
head页面的01234表示的是分片,粗框表示的是主分片,细框表示的是副本,
节点宕机(故障转移):
当date节点宕机:集群状态为黄色,表示主节点可用,副本节点不完全可用。过一段时间观察,发现节点列表中没有宕机的节点,副本节点分配到了未宕机的其他节点,集群状态恢复为绿色。
当把date节点恢复后,这个date节点重新加入了集群,并且重新分配了节点信息。
当主节点宕机: 集群装填变为黄色,集群对master进行了重新选举,选举了新的master , ,过一段时间观察,发现节点列表没有了原先宕机的主节点,集群状态恢复为绿色。
当宕机的主节点恢复后,这个节点加不到集群中了。这就是集群中的脑裂问题。
脑裂问题:
指挥master变成了多个。
解决方案:不能让节点很容易的变成master,必须有多个节点认可后才可以。 设置minimum_naster_nodes的大小为2(所有节点的都设置),官方推荐(N/2)+1 ,N为集群中节点数。
分布式文档存储路由:在elasitcsearch中,会采用计算的方式来确定存储到哪个节点,计算公式如下:
shard = hash(routing) % number_of_primary_shards
routing值是一个任意字符串,它默认是_id但也可以自定义。
这个routing字符串通过哈希函数生成一个数字,然后除以主切片的数量得到一个余数(remainder),余数的范围永远是0到number_of_primary_shards - 1,这个数字就是特定文档所在的分片。 这就是为什么创建了主分片后不能修改的原因。
写操作: 新建、索引、删除都是写操作,比如对节点三进行写操作,节点三会去请求主节点,在主节点上成功完成了才能复制到相关的复制分片守丧。
搜索文档: 文档能够从主分片或任意一个复制分片进行检索。
全文搜索: 当文档可能分散在各个节点上,那么在分布式的情况下,搜索分为两个阶段,搜索+取回。
客户端发送一个search搜索请求给node3,创建一个长度为from+size的空优先级队列,node3z转发这个搜索到索引中的每个分片的副本或副本,每个分片在本地执行这个查询并将结果返回,一旦所有的文档都返回了,node3将这些值合并到自己的优先队列里并返回给客户端。
java客户端:
在Elasticsearch中,为java提供了2种客户端,一种是REST风格的客户端,另一种是Java API的客户端。
REST又分高级客户端和低级客户端。(直接发送POST/GET请求的方式)
低级:
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>6.5.4</version>
</dependency>
与使用RESTful api 几乎一致。
高级:
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.5.4</version>
</dependency>
Spring Data 提供了简化 Elasticsearch操作:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
编辑properties:
spring.application.name = itcast-elasticsearch
spring.data.elasticsearch.cluster-name=es-itcast-cluster
spring.data.elasticsearch.cluster-
nodes=172.16.55.185:9300,172.16.55.185:9301,172.16.55.185:9302
#这里的9300是api端口,restful端口监听的是9200,api监听的9300
编写User对象:
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "itcast", type = "user", shards = 6, replicas = 1)
public class User {
@Id
private Long id;
@Field(store = true)
private String name;
@Field
private Integer age;
@Field
private String hobby;
}
新增数据:
@Test
public void testSave(){
User user = new User();
user.setId(1001L);
user.setAge(20);
user.setName("张三");
user.setHobby("足球、篮球、听音乐");
IndexQuery indexQuery = new IndexQueryBuilder().withObject(user).build();
String index = this.elasticsearchTemplate.index(indexQuery);
System.out.println(index);
}
批量插入数据:
@Test
public void testBulk() {
List list = new ArrayList();
for (int i = 0; i < 5000; i++) {
User user = new User();
user.setId(1001L + i);
user.setAge(i % 50 + 10);
user.setName("张三" + i);
user.setHobby("足球、篮球、听音乐");
IndexQuery indexQuery = new
IndexQueryBuilder().withObject(user).build();
list.add(indexQuery);
}
Long start = System.currentTimeMillis();
this.elasticsearchTemplate.bulkIndex(list);
System.out.println("用时:" + (System.currentTimeMillis() - start));
}
更新数据:
/**
* 局部更新,全部更新使用index覆盖即可
*/
@Test
public void testUpdate() {
IndexRequest indexRequest = new IndexRequest();
indexRequest.source("age", "30");
UpdateQuery updateQuery = new UpdateQueryBuilder()
.withId("1001")
.withClass(User.class)
.withIndexRequest(indexRequest).build();
this.elasticsearchTemplate.update(updateQuery);
}
删除数据
@Test
public void testDelete(){
this.elasticsearchTemplate.delete(User.class, "1001");
}
搜索
@Test
public void testSearch(){
PageRequest pageRequest = PageRequest.of(1,10); //设置分页参数
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchQuery("name", "张三")) // match查询
.withPageable(pageRequest)
.build();
AggregatedPage<User> users =
this.elasticsearchTemplate.queryForPage(searchQuery, User.class);
System.out.println("总页数:" + users.getTotalPages()); //获取总页数
for (User user : users.getContent()) { // 获取搜索到的数据
System.out.println(user);
}
}