docker 安装 ES & Kibana
version: "3.1"
services:
elasticsearch:
image: elasticsearch:6.8.11
restart: always
container_name: elasticsearch
environment:
- cluster.name=docker-cluster
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- ./esdata:/usr/share/elasticsearch/data
ports:
- 9200:9200
kibana:
image: kibana:6.8.11
restart: always
container_name: kibana
ports:
- 5601:5601
environment:
- elasticsearch_url=http://192.168.111.134:9200
depends_on:
- elasticsearch
volumes:
esdata:
driver: local
docker安装常见Bug
-
elasticsearch用docker启动一会之后服务自动关闭的问题
分配内存太小,需要将vm.max_map_count的值调大,网上查资料,得知用命令的方式来设置vm.max_map_count,命令如下:
sysctl -w vm.max_map_count=2621441
查看vm.max_map_count命令:
sysctl -a|grep vm.max_map_count
但是以上方法在重启虚拟机之后就不生效,如果想要一直生效的话,到 /etc目录下编辑sysctl.conf文件,添加vm.max_map_count=262144就可以了。
保存文件之后用sysctl -a|grep vm.max_map_count命令查看,显示的还是修改之前的值,此时需要重启虚拟机才能生效
-
docker 启动 elasticsearch 异常 Failed to create node environment
chmod 777 挂载目录路径
倒排索引
倒排索引源于实际应用中需要根据属性的值来查找记录。这种索引表中的每一项都包括一个属性值和具有该属性值的各记录的地址。由于不是由记录来确定属性值,而是由属性值来确定记录的位置,因而称为倒排索引(inverted index)。带有倒排索引的文件我们称为倒排索引文件,简称倒排文件。
安装中文分词器
docker exec -it elasticsearch bash
# 去github上下载对应版本的ik(zip)
cd /usr/share/elasticsearch/bin/
./elasticsearch-plugin install http://192.168.111.135/resource/elasticsearch-analysis-ik-6.8.11.zip
简单测试一下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M5T4ogWm-1600263695594)(image-20200906142202889.png)]
ES 的 RESTful 语法
# 创建一个索引
PUT /world
{
"settings": {
# 指定分片数
"number_of_shards": 5,
# 指定备份数
"number_of_replicas": 1
},
"mappings": {
"person":{
"properties":{
"address":{
"type":"text",
"analyzer": "ik_max_word",
"index":true,
"store":false
},
"name":{
"type":"keyword"
},
"age":{
"type":"short"
}
}
}
}
}
# 添加文档,自动生成id(这里的id默认是一串字符,不建议使用)
POST /world/person
{
"address":"湖北省随州市金泰国际",
"name":"小钱",
"age":21
}
# 指定id,可以添加也可以用来修改(这里的修改是删除原有再添加的过程)
PUT /world/person/1
{
"address":"湖北省随州市尚市中心小学",
"name":"小河",
"age":20
}
# 修改文档(建议使用这种非覆盖式的修改)
POST /world/person/1/_update
{
"doc":{
"name":"小钱钱"
}
}
# 根据id删除文档
DELETE /world/person/qscjY3QBS4FSq2X48CAk
# 查看索引
GET /world
# 删除索引
DELETE /world
java ES 常用操作
<!--elasticsearch-->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.8.11</version>
</dependency>
<!--elasticsearch的高级API-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.8.11</version>
</dependency>
ObjectMapper objectMapper = new ObjectMapper();
RestHighLevelClient restHighLevelClient = ESClient.getRestClient();
String index = "world";
String type = "person";
@org.junit.Test
public void test1() {
RestHighLevelClient restHighLevelClient = ESClient.getRestClient();
System.out.println("OK");
}
/**
* 创建索引
*/
@org.junit.Test
public void test2() throws IOException {
//准备索引的settings属性
Settings.Builder settings = Settings.builder()
.put("number_of_shards", 5)
.put("number_of_replicas", 1);
//准备索引结构信息
XContentBuilder xContentBuilder = JsonXContent.contentBuilder()
.startObject()
.startObject("properties")
.startObject("address")
.field("type", "text")
.field("analyzer", "ik_max_word")
.endObject()
.startObject("name")
.field("type", "keyword")
.endObject()
.startObject("age")
.field("type", "short")
.endObject()
.endObject()
.endObject();
//将settings和mappings封装到Request
CreateIndexRequest createIndexRequest = new CreateIndexRequest(index)
.settings(settings)
.mapping(type, xContentBuilder);
//通过RestHighLevelClient去执行操作
CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
System.out.println(createIndexResponse.toString());
}
/**
* 检查索引是否存在
*/
@org.junit.Test
public void test3() throws IOException {
GetIndexRequest getIndexRequest = new GetIndexRequest();
getIndexRequest.indices(index);
//通过client去操作
boolean exists = restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
System.out.println(exists);
}
/**
* 删除索引
*/
@org.junit.Test
public void test4() throws IOException {
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest();
deleteIndexRequest.indices(index);
AcknowledgedResponse delete = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
System.out.println(delete.isAcknowledged());
}
/**
* 创建一个文档
*/
@org.junit.Test
public void test5() throws IOException {
Person person = new Person();
person.setId(4L);
person.setName("小钱");
person.setAddress("随州市");
person.setAge((short) 21);
String string = objectMapper.writeValueAsString(person);
IndexRequest indexRequest = new IndexRequest(index, type, person.getId().toString());
indexRequest.source(string, XContentType.JSON);
IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
System.out.println(indexResponse.getResult().toString());
}
/**
* 更新一个文档
*/
@org.junit.Test
public void test6() throws IOException {
Map<String, Object> updateDoc = new HashMap<>();
updateDoc.put("address", "黑龙江");
UpdateRequest updateRequest = new UpdateRequest(index, type, "2");
updateRequest.doc(updateDoc);
UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
System.out.println(updateResponse.getResult().toString());
}
/**
* 删除文档
*/
@org.junit.Test
public void test7() throws IOException {
DeleteRequest deleteRequest = new DeleteRequest(index, type, "1");
DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
System.out.println(deleteResponse.getResult().toString());
}
/**
* 批量新增文档
*/
@org.junit.Test
public void test8() throws IOException {
Person person1 = new Person(11L, "武汉市", (short) 12, "小王");
String string1 = objectMapper.writeValueAsString(person1);
Person person2 = new Person(12L, "武汉市", (short) 121, "小王");
String string2 = objectMapper.writeValueAsString(person2);
Person person3 = new Person(13L, "武汉市", (short) 122, "小王");
String string3 = objectMapper.writeValueAsString(person3);
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.add(new IndexRequest(index, type, person1.getId().toString()).source(string1, XContentType.JSON));
bulkRequest.add(new IndexRequest(index, type, person2.getId().toString()).source(string2, XContentType.JSON));
bulkRequest.add(new IndexRequest(index, type, person3.getId().toString()).source(string3, XContentType.JSON));
BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
System.out.println(bulkResponse.toString());
}
/**
* 批量删除
*/
@org.junit.Test
public void test9() throws IOException {
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.add(new DeleteRequest(index, type, "2"));
bulkRequest.add(new DeleteRequest(index, type, "3"));
bulkRequest.add(new DeleteRequest(index, type, "4"));
BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
System.out.println(bulkResponse.toString());
}
搜索实践
数据准备
使用如下的python代码爬取大概50000条左右的京东商品数据,作为搜索引擎的实验数据
import sqlite3
# 初始化数据库
def init_connection():
connect = sqlite3.connect('jd.db')
connect.execute('''CREATE TABLE product(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
p_name TEXT NOT NULL,
p_price INT NOT NULL,
p_shop CHAR(200)
);''')
def get_connection():
connect = sqlite3.connect('jd.db')
return connect
# 插入一条数据
def insert_product(connect, p_name, p_price, p_shop):
sql = "INSERT INTO product (p_name, p_price, p_shop) VALUES ('" + p_name + "'," + p_price + ",'" + p_shop + "')"
connect.execute(sql)
connect.commit()
import requests
from bs4 import BeautifulSoup
import sqlite_utils
def start():
# 用来存储数据的sqlite
connection = sqlite_utils.get_connection()
base_url = "https://search.jd.com/Search?keyword=笔记本散热"
# GET类型请求(不允许重定向,以此来判断是否到最后一页)
get_result = requests.get(base_url, allow_redirects=False)
page_num = -1
# 爬取所有的页
for i in range(1, 100):
page_num = page_num + 2
print("总页数:100 当前爬取页:" + str(page_num))
url = base_url + "&page=" + str(page_num)
result = requests.get(url, allow_redirects=False)
# 指定html解析器,以适应在不同环境下运行
soup1 = BeautifulSoup(result.text, "html.parser")
scenery_list = soup1.find_all(name="div", attrs={"class": "gl-i-wrap"})
for scenery in scenery_list:
text = str(scenery)
soup1 = BeautifulSoup(text, "html.parser")
product_name = soup1.find(name="div", attrs={"class", "p-name p-name-type-2"})
if product_name is None:
continue
product_name_str = product_name.find(name="em").text
product_price = soup1.find(name="div", attrs={"class", "p-price"})
if product_price is None:
continue
product_price_str = product_price.find(name="i").text
product_shop = soup1.find(name="span", attrs={"class", "J_im_icon"})
if product_shop is None:
continue
product_shop_str = product_shop.find(name="a").text
sqlite_utils.insert_product(connection, product_name_str, product_price_str, product_shop_str)
# 关闭文件
connection.close()
if __name__ == '__main__':
try:
start()
except OSError:
pass
将sqlite中的数据放入ES中
public class Main {
RestHighLevelClient restHighLevelClient = EsClient.getRestClient();
String index = "sky";
String type = "product";
ObjectMapper objectMapper = new ObjectMapper();
public static void main(String[] args) throws SQLException, IOException {
Main main = new Main();
//创建索引
main.createIndex();
//初始化数据
main.initDoc();
}
public void initDoc() throws SQLException, IOException {
Connection connection = SqliteUtils.getConnection("D:\\code\\demo-world\\elasticsearch\\src\\main\\resources\\jd.db");
ResultSet resultSet = SqliteUtils.executeQuery(connection, "select * from product");
while (resultSet.next()) {
Product product = new Product();
String id = resultSet.getString(1);
String pName = resultSet.getString(2);
String pPrice = resultSet.getString(3);
String pShop = resultSet.getString(4);
product.setpName(pName);
product.setpPrice(Double.parseDouble(pPrice));
product.setpShop(pShop);
String string = objectMapper.writeValueAsString(product);
IndexRequest indexRequest = new IndexRequest(index, type, id);
indexRequest.source(string, XContentType.JSON);
IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
System.out.print(">");
}
}
public void createIndex() throws IOException {
Settings.Builder settings = Settings.builder()
.put("number_of_shards", 5)
.put("number_of_replicas", 1);
XContentBuilder xContentBuilder = JsonXContent.contentBuilder()
.startObject()
.startObject("properties")
.startObject("pName")
.field("type", "text")
.field("analyzer", "ik_max_word")
.endObject()
.startObject("pPrice")
.field("type", "integer")
.endObject()
.startObject("pShop")
.field("type", "text")
.field("analyzer", "ik_max_word")
.endObject()
.endObject()
.endObject();
CreateIndexRequest createIndexRequest = new CreateIndexRequest(index)
.settings(settings)
.mapping(type, xContentBuilder);
CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
System.out.println(createIndexResponse.toString());
}
}
public class EsClient {
public static RestHighLevelClient getRestClient() {
HttpHost httpHost = new HttpHost("192.168.111.134", 9200);
RestClientBuilder restClientBuilder = RestClient.builder(httpHost);
return new RestHighLevelClient(restClientBuilder);
}
}
public class SqliteUtils {
public SqliteUtils() {
}
public static Connection getConnection(String url) throws SQLException {
String connPath = String.format("jdbc:sqlite:%s", url);
Connection conn = null;
try {
String driverClass = "org.sqlite.JDBC";
Class.forName(driverClass);
System.out.println("数据库驱动加载成功");
conn = DriverManager.getConnection(connPath);
System.out.println("数据库连接成功");
} catch (ClassNotFoundException var3) {
var3.printStackTrace();
} catch (SQLException var4) {
var4.printStackTrace();
throw var4;
}
return conn;
}
public static ResultSet executeQuery(Connection conn, String sql) throws SQLException {
Statement statement = conn.createStatement();
return statement.executeQuery(sql);
}
}
public class Product {
@JsonIgnore
private Integer id;
private String pName;
private Double pPrice;
private String pShop;
}
各种Java查询的公共代码
/**
* 查询
*/
public void search(QueryBuilder queryBuilder) throws IOException {
SearchRequest searchRequest = new SearchRequest(index);
searchRequest.types(type);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.from(0);
searchSourceBuilder.size(20);
searchSourceBuilder.query(queryBuilder);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHits searchHits = searchResponse.getHits();
System.out.println(searchHits.getTotalHits());
for (SearchHit hit : searchHits.getHits()) {
Map<String, Object> result = hit.getSourceAsMap();
System.out.println(result);
}
}
id & ids
# id查询
GET /sky/product/2
# ids查询
POST /sky/product/_search
{
"query": {
"ids": {
"values": [1,2,8]
}
}
}
/**
* id
*/
public void idQuery() throws IOException {
GetRequest getRequest = new GetRequest(index, type, "1");
GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
System.out.println(getResponse.getSourceAsMap());
}
/**
* ids
*/
public void idsQuery() throws IOException {
search(QueryBuilders.idsQuery().addIds("1", "2", "8"));
}
term & terms
# term
POST /sky/product/_search
{
"from": 0,
"size": 20,
"query": {
"term": {
"pShop": {
"value": "联想"
}
}
}
}
# terms
POST /sky/product/_search
{
"from": 0,
"size": 20,
"query": {
"terms": {
"pShop": [
"华为",
"小米"
]
}
}
}
/**
* term查询,关键字查询前不分词,因此 ‘联想天佑专卖店’ 匹配不到 ‘联想天佑专卖店’
*/
public void termQuery() throws IOException {
search(QueryBuilders.termQuery("pShop", "联想"));
}
/**
* terms查询,与terms同义,不同之处在于可以指定多个匹配条件
*/
public void termsQuery() throws IOException {
search(QueryBuilders.termsQuery("pShop", "小米", "华为"));
}
match & match(and or) & multi_match
# match查询,依据字段类型的不同,采用不同的查询方式
POST /sky/product/_search
{
"query": {
"match": {
"pName": "男袜子"
}
}
}
# and or 方法连接
POST /sky/product/_search
{
"query": {
"match": {
"pName": {
"query": "小米笔记本,台式机",
"operator": "and"
}
}
}
}
# multi_match 指定再多个field中查询
POST /sky/product/_search
{
"query": {
"multi_match": {
"query": "小米笔记本",
"fields": ["pName","pShop"]
}
}
}
/**
* match查询
*/
public void matchQuery() throws IOException {
search(QueryBuilders.matchQuery("pName", "小米笔记本"));
}
/**
* match查询(and or)
*/
public void matchBooleanQuery() throws IOException {
search(QueryBuilders.matchQuery("pName", "小米笔记本 台式机").operator(Operator.AND));
}
/**
* multi_match 指定再多个field中查询
*/
public void multiMatchQuery() throws IOException {
search(QueryBuilders.multiMatchQuery("小米笔记本", "pName", "pShop"));
}
perfix
# prefix 前缀匹配(如果没有该前缀的数据,然后在其他位置匹配)
POST /sky/product/_search
{
"query": {
"prefix": {
"pName": {
"value": "华为"
}
}
}
}
/**
* prefix前置查询
*/
public void prefixQuery() throws IOException {
search(QueryBuilders.prefixQuery("pName", "小米"));
}
fuzzy
# fuzzy查询 模糊查询(可以有错别字)
POST /sky/product/_search
{
"query": {
"fuzzy": {
"pShop": {
"value": "笔大本",
"prefix_length": 1
}
}
}
}
/**
* fuzzy 查询 模糊查询(可以有错别字)
*/
public void fuzzyQuery() throws IOException {
search(QueryBuilders.fuzzyQuery("pShop", "笔大本").prefixLength(1));
}
wildcard
# wildcard 查询,类似like
POST /sky/product/_search
{
"query": {
"wildcard": {
"pName": {
"value": "中国??"
}
}
}
}
/**
* wildcard 查询,类似like
*/
public void wildcardQuery() throws IOException {
search(QueryBuilders.wildcardQuery("pName", "中国??"));
}
range
# range 范围查询 (gte包含等于,gt不包含)
POST /sky/product/_search
{
"query": {
"range": {
"pPrice": {
"gte": 10000,
"lte": 10100
}
}
}
}
/**
* range 范围查询 (gte包含等于,gt不包含)
*/
public void rangeQuery() throws IOException {
search(QueryBuilders.rangeQuery("pPrice").gte(10000).lte(10100));
}
regexp
# regexp 正则表达式查询 (prefix,fuzzy,wildcard ,regexp 效率略低)
POST /sky/product/_search
{
"query": {
"regexp": {
"pName": "华为.*"
}
}
}
/**
* regexp 正则表达式查询 (prefix,fuzzy,wildcard ,regexp 效率略低)
*/
public void regexpQuery() throws IOException {
search(QueryBuilders.regexpQuery("pName", "华为.*"));
}
scroll
ES对from+size大小有限制,from和size之和不能超过1W
from+size在ES查询数据的方式
- 将用户的关键字分词
- 去分词库中检索,得到多个 文档id
- 使用这些id 去各个分片中拿去数据(倒排索引)(耗时较长)
- 将获取的数据依据 score 值进行排序(score为匹配度,越大匹配度越高,此步骤较为耗时)
- 依据from,size的值,舍弃数据
- 返回结果
scroll + size 的查询方式
- 将用户的关键字分词
- 去分词库中检索,得到多个 文档id
- 将获得的文档id存入ES的上下文(内存中)
- 依据你指定的size去ES中检索指定的数据,拿完数据的文档id,会从上下文中移除
- 如果需要下一页的数据,直接去ES的上下文。
Scorll查询方式效率高,但不适合做实事数据搜索
# scroll=1m 代表上下文有效期(分钟)
POST /sky/product/_search?scroll=1m
{
"query": {
"match": {
"pName": "联想"
}
},
"size": 2
, "sort": [
{
"pPrice": {
"order": "asc"
}
}
]
}
POST /_search/scroll
{
"scroll_id":"DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAQ3Fm1QMFBlbUlOUkgtTllIS3plM2k5S1EAAAAAAAAEOxZtUDBQZW1JTlJILU5ZSEt6ZTNpOUtRAAAAAAAABDgWbVAwUGVtSU5SSC1OWUhLemUzaTlLUQAAAAAAAAQ5Fm1QMFBlbUlOUkgtTllIS3plM2k5S1EAAAAAAAAEOhZtUDBQZW1JTlJILU5ZSEt6ZTNpOUtR",
"scroll":"1m"
}
# 删除上下文
DELETE /_search/scroll/DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAQ3Fm1QMFBlbUlOUkgtTllIS3plM2k5S1EAAAAAAAAEOxZtUDBQZW1JTlJILU5ZSEt6ZTNpOUtRAAAAAAAABDgWbVAwUGVtSU5SSC1OWUhLemUzaTlLUQAAAAAAAAQ5Fm1QMFBlbUlOUkgtTllIS3plM2k5S1EAAAAAAAAEOhZtUDBQZW1JTlJILU5ZSEt6ZTNpOUtR
public void scrollQuery() throws IOException {
SearchRequest searchRequest = new SearchRequest(index);
searchRequest.types(type);
searchRequest.scroll(TimeValue.timeValueMinutes(1L));
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.size(20);
searchSourceBuilder.sort("pPrice", SortOrder.DESC);
searchSourceBuilder.query(QueryBuilders.matchQuery("pName", "联想"));
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
String scrollId = searchResponse.getScrollId();
System.out.println("-------------首页-------------");
for (SearchHit hit : searchResponse.getHits().getHits()) {
System.out.println(hit.getSourceAsMap());
}
int i = 1;
while (true) {
i++;
SearchScrollRequest searchScrollRequest = new SearchScrollRequest(scrollId);
searchScrollRequest.scroll(TimeValue.timeValueMinutes(1L));
SearchResponse response = restHighLevelClient.scroll(searchScrollRequest, RequestOptions.DEFAULT);
SearchHit[] hits = response.getHits().getHits();
if (hits != null && hits.length > 0) {
System.out.println("-------------下一页-------------" + i);
for (SearchHit hit : hits) {
System.out.println(hit.getSourceAsMap());
}
} else {
System.out.println("-------------结束-------------" + i);
break;
}
}
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
clearScrollRequest.addScrollId(scrollId);
ClearScrollResponse clearScrollResponse = restHighLevelClient.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
System.out.println("删除上下文:" + clearScrollResponse.isSucceeded());
}
delete-by-query
查询指定的文档,然后删除
如果你需要删除的内容是索引中的大部分数据,推荐创建一个全新的索引,将保留的文档内容添加到全新的索引。
POST /sky/product/_delete_by_query
{
"query": {
"match": {
"pName": "西瓜"
}
}
}
public void deleteByQuery() throws IOException {
DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(index);
deleteByQueryRequest.types(type);
deleteByQueryRequest.setQuery(QueryBuilders.matchQuery("pName", "联想"));
BulkByScrollResponse bulkByScrollResponse = restHighLevelClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
System.out.println(bulkByScrollResponse.toString());
}
复合查询
bool查询
must 代表and查询
should 代表or查询
must_not 代表Not意思
POST /sky/product/_search
{
"query": {
"bool": {
"must": [
{"match": {
"pName": "小米"
}},
{"match": {
"pShop": "专卖店"
}}
]
}
}
}
/**
* 复合查询
*/
public void boolQuery() throws IOException {
SearchRequest searchRequest = new SearchRequest(index);
searchRequest.types(type);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.from(0);
searchSourceBuilder.size(20);
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.matchQuery("pName", "小米"));
boolQueryBuilder.must(QueryBuilders.matchQuery("pShop", "专卖店"));
searchSourceBuilder.query(boolQueryBuilder);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHits searchHits = searchResponse.getHits();
System.out.println(searchHits.getTotalHits());
for (SearchHit hit : searchHits.getHits()) {
Map<String, Object> result = hit.getSourceAsMap();
System.out.println(result);
}
}
boosting
影响 _score
filter查询
query 计算score,排序,不会缓存数据
filter 不计算score,不排序,会缓存数据
高亮显示
POST /sky/product/_search
{
"query": {
"bool": {
"must": [
{"match": {
"pName": "小米"
}},
{"match": {
"pShop": "专卖店"
}}
]
}
},
"highlight": {
# 设置高亮显示的属性
"fields": {
"pName": {},
"pShop": {}
},
"pre_tags": "<span color='red'>",
"post_tags": "</span>",
# 显示字数
"fragment_size": 15
}
}
/**
* 高亮查询
*/
public void highlightQuery() throws IOException {
SearchRequest searchRequest = new SearchRequest(index);
searchRequest.types(type);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.from(0);
searchSourceBuilder.size(20);
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.matchQuery("pName", "小米"));
boolQueryBuilder.must(QueryBuilders.matchQuery("pShop", "专卖店"));
searchSourceBuilder.query(boolQueryBuilder);
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder
.field("pName", 10)
.field("pShop", 15)
.preTags("<span color='red'>")
.postTags("</span>");
searchSourceBuilder.highlighter(highlightBuilder);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHits searchHits = searchResponse.getHits();
System.out.println(searchHits.getTotalHits());
for (SearchHit hit : searchHits.getHits()) {
System.out.println(hit.getHighlightFields().get("pName"));
System.out.println(hit.getHighlightFields().get("pShop"));
}
}
聚合查询
POST /sky/product/_search
{
"aggs": {
"agg": {
"range": {
"field": "pPrice",
"ranges": [
{
"from": 100,
"to": 200
},
{
"from": 200,
"to": 300
},
{
"from": 300,
"to": 400
}
]
}
}
}
}
/**
* 聚合查询
*/
public void aggregateQuery() throws IOException {
SearchRequest searchRequest = new SearchRequest(index);
searchRequest.types(type);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.aggregation(AggregationBuilders.range("agg").field("pPrice")
.addRange(100, 200)
.addRange(200, 300)
.addRange(300, 400));
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
Range range = searchResponse.getAggregations().get("agg");
for (Range.Bucket bucket : range.getBuckets()) {
String key = bucket.getKeyAsString();
Object from = bucket.getFrom();
Object to = bucket.getTo();
long docCount = bucket.getDocCount();
System.out.printf("key:%s,from:%s,to:%s,docCount:%s%n", key, from, to, docCount);
}
}