ES基本使用
package com.paic;
import java.net.InetAddress;
import java.text.MessageFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.get.MultiGetItemResponse;
import org.elasticsearch.action.get.MultiGetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import com.google.gson.Gson;
public class ElasticSearchTester {
public static String INDEX = "oms";
public static String TYPE = "order";
public static TransportClient client;
static {
try {
Settings settings = Settings.builder().put("cluster.name", "elasticsearch").build();
client = new PreBuiltTransportClient(settings);
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));
System.out.println("---ES连接成功!---");
if(! client.admin().indices().exists(new IndicesExistsRequest(INDEX)).actionGet().isExists()){
creatIndex();
// {
// "id": 2,
// "order_no": "OB-755679845",
// "product": "SE0033",
// "warehouse": "7550VB",
// "items": 120,
// "container": "379900890889765",
// "createTime": "Oct 2, 2019 4:22:56 PM"
// }
creatIndexByBuilder("1", "OB-755677823", "SE0001", "7550VB", 50, null);
creatIndexByBuilder("2", "OB-755679845", "SE0033", "7550VB", 180, "2346986");
creatIndexByBuilder("3", "IN-755673490", "SE0001", "010VSB", 130, null);
creatIndexByBuilder("4", "OB-785677343", "SE0033", "DXD_WH", 30, null);
creatIndexByBuilder("5", "IN-785677343", "SE0033", "DXD_WH", 90, "2346524");
// POST http://localhost:9200/oms/order
// {\"id\":1,\"order_no\":\"OB-755677823\",\"product\":\"SE0001\",\"warehouse\":\"7550VB\",\"items\":50,\"createTime\":\"Oct 2, 2019 4:32:46 PM\"}{\"id\":2,\"order_no\":\"OB-755679845\",\"product\":\"SE0033\",\"warehouse\":\"7550VB\",\"items\":120,\"container\":\"379900890889765\",\"createTime\":\"Oct 2, 2019 4:22:56 PM\"}{\"id\":3,\"order_no\":\"IN-755673490\",\"product\":\"SE0001\",\"warehouse\":\"010VB\",\"items\":80,\"createTime\":\"Oct 2, 2019 4:30:46 PM\"}{\"id\":4,\"order_no\":\"OB-785677343\",\"product\":\"SE0033\",\"warehouse\":\"DXD_WH\",\"items\":150,\"createTime\":\"Oct 2, 2019 6:32:46 PM\"}{\"id\":5,\"order_no\":\"IN-785677343\",\"product\":\"SE0033\",\"warehouse\":\"DXD_WH\",\"items\":150,\"container\":\"379900890990232\",\"createTime\":\"Oct 2, 2019 6:32:46 PM\"}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
// creatIndex();
// creatIndexByBuilder();
// getMultiData();
// matchAllQuery();
// query_2();
query_3();
}
public static void query_2() {
BoolQueryBuilder builder = QueryBuilders.boolQuery();
// WHERE product='SE0001'
// builder.must(QueryBuilders.matchQuery("product", "SE0001"));
// WHERE product='SE0001' and order_no 包含'OB'
builder.must(QueryBuilders.matchQuery("product", "SE0001"));
builder.must(QueryBuilders.matchQuery("order_no", "OB"));
// WHERE warehouse='010VB' or (warehouse ='7550VB' and product='SE0033')
// builder.should(QueryBuilders.matchQuery("warehouse", "010VSB"));
// builder.should(QueryBuilders.boolQuery()
// .must(QueryBuilders.matchQuery("warehouse", "7550VB"))
// .must(QueryBuilders.matchQuery("product", "SE0033")));
// WHERE container != null or (warehouse='010VSB' or items > 130)
// builder.should(QueryBuilders.existsQuery("container"));
// builder.should(QueryBuilders.boolQuery()
// .should(QueryBuilders.matchQuery("warehouse", "010VSB"))
// .should(QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery("items").gte(130))));//gt: > gte: >= lt: < lte: <=
SearchRequestBuilder reqBuilder = client.prepareSearch(INDEX).setTypes(TYPE).setQuery(builder);
SearchResponse searchResponse = reqBuilder.get();
SearchHits hits = searchResponse.getHits();// 获取命中数,查询结果有多少对象
System.out.println("参数:\n"+reqBuilder.toString());
System.out.println("查询到" + hits.totalHits + "条");
for (SearchHit hit : hits) {
System.out.println(hit.getSourceAsString());
}
}
public static void query_3() {
SearchRequestBuilder sbuilder = client.prepareSearch(INDEX).setTypes(TYPE);
TermsAggregationBuilder teamAgg= AggregationBuilders.terms("product_count").field("product");
sbuilder.addAggregation(teamAgg);
SearchResponse response = sbuilder.execute().actionGet();
System.out.println(response);
StringTerms terms = response.getAggregations().get("product_count");
Iterator<StringTerms.Bucket> teamBucketIt = terms.getBuckets().iterator();
while (teamBucketIt .hasNext()) {
Terms.Bucket bucket = teamBucketIt.next();
String team = (String) bucket.getKey();
long count = bucket.getDocCount();
System.out.println(team + " " + count);
}
}
public static void creatIndex() {
client.admin().indices().prepareCreate(INDEX).get();
}
public static void creatIndexByBuilder(String id, String orderNo, String product, String warehouse, int items, String container) {
try {
XContentBuilder builder = XContentFactory.jsonBuilder()
.startObject()
.field("id", id)
.field("order_no", orderNo)
.field("product", product)
.field("warehouse", warehouse)
.field("items", items)
.field("container", container)
.field("createTime", new Date())
.endObject();
IndexResponse indexResponse = client.prepareIndex(INDEX, TYPE, null).setSource(builder).execute()
.actionGet();
System.out.println(MessageFormat.format("[index:{0}] [type:{1}] [id:{2}] [version:{3}] [result:{4}]",
indexResponse.getIndex(), indexResponse.getType(), indexResponse.getId(), indexResponse.getVersion(),
indexResponse.getResult()));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Map<String, Object> jsonDoc = new HashMap<String, Object>();
* jsonDoc.put("id", "2"); jsonDoc.put("title", "基于Lucene的搜索服务器");
* jsonDoc.put("content", "它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口");
*/
public static void creatIndexByMap(Map<String, Object> jsonDoc) {
IndexResponse indexResponse = client.prepareIndex(INDEX, TYPE, null).setSource(jsonDoc).execute().actionGet();
// 3、打印返回的结果
System.out.println(MessageFormat.format("[index:{0}] [type:{1}] [id:{2}] [version:{3}] [result:{4}]",
indexResponse.getIndex(), indexResponse.getType(), indexResponse.getId(), indexResponse.getVersion(),
indexResponse.getResult()));
}
public static void getMultiData() {
// 1、查询多个文档
MultiGetResponse response = client.prepareMultiGet().add(INDEX, TYPE, "1").add(INDEX, TYPE, "2", "3")
.add(INDEX, TYPE, "2").get();
// 2、遍历返回的结果
for (MultiGetItemResponse itemResponse : response) {
GetResponse getResponse = itemResponse.getResponse();
// 如果获取到查询结果
if (getResponse.isExists()) {
String sourceAsString = getResponse.getSourceAsString();
System.out.println(sourceAsString);
}
}
}
public static void matchAllQuery() {
// 1.执行查询(查询所有)
SearchResponse searchResponse = client.prepareSearch(INDEX).setTypes(TYPE)
.setQuery(QueryBuilders.matchAllQuery()).get();
// 2、打印查询结果
SearchHits hits = searchResponse.getHits();// 获取命中数,查询结果有多少对象
System.out.println("查询结果一共有" + hits.totalHits + "条");
for (SearchHit hit : hits) {
System.out.println(hit.getSourceAsString());
}
}
}
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>5.6.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>5.6.0</version>
</dependency>
ES映射
为了能够将时间域视为时间,数字域视为数字,字符串域视为全文或精确值字符串, Elasticsearch 需要知道每个域中数据的类型。这个信息包含在映射中,索引中每个文档都有类型 。每种类型都有它自己的映射
ES支持如下域类型:
简单类型
-
字符串:
string
-
整数 :
byte
,short
,integer
,long
-
浮点数:
float
,double
-
布尔型:
boolean
-
日期:
date
复杂类型
-
对象数据类型: object,单独的JSON对象。
-
嵌套数据类型: nested,关于JSON对象的数组。
地理类型
-
经纬度
- 查找一定范围内的地理点,这个范围可以是相对于一个中心点的固定距离,也可以是多边形或者地理散列单元
- 通过地理位置或者相对于中心点的距离聚合文档
- 通过距离对文档进行排序
专门数据类型
-
IPv4数据类型
- IPv4字段本质上是一个长整型字段,接受IPv4地址并作为长整型值进行索引(192.168.0 -> 1921680)
默认提供了以下映射规则(动态映射),新增文档时,会根据值类型按下面的规则进行猜测,比如{“age”:“25”}会将age视为字符串类型,{“age”:25}会将age视为数字类型。映射操作会在文档的每个层级都会做,即嵌套很多层对JSON一样可以被映射
JSON type | 域 type |
---|---|
布尔型: true 或者 false | boolean |
整数: 123 | long |
浮点数: 123.45 | double |
字符串,有效日期: 2014-09-15 | date |
字符串: foo bar | string |
创建一个索引
localhost:9200/map/order
{"id":1,"tag":"java技术博客","author":"bob","createTime":"2014-09-15","content":{"title":"ES的基本使用","theme":"黑礁石主题","rows":150,"body":{"data":"ES搜索引擎是为解决传统搜索工具易用性问题,应用广泛","quote":["http://www.baidu.com/","http://www.sina.com"]}}}
查看映射
localhost:9200/map/_mapping/order
{"map":{"mappings":{"order":{"properties":{"author":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"content":{"properties":{"body":{"properties":{"data":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"quote":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}}}},"rows":{"type":"long"},"theme":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"title":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}}}},"createTime":{"type":"date"},"id":{"type":"long"},"tag":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}}}}}}}
即使没有加映射也会按默认规则进行映射,并且嵌套层级节点也会被映射到
多层级JSON对象实际上会被映射成键值对形式(因为Lucene不理解内部对象。 Lucene文档是由一组键值对列表组成的 )
{
"tweet": "Elasticsearch is very flexible",
"user": {
"id": "@johnsmith",
"gender": "male",
"age": 26,
"name": {
"full": "John Smith",
"first": "John",
"last": "Smith"
}
}
}
# 实际存储的结构
{
"tweet": [elasticsearch, flexible, very],
"user.id": [@johnsmith],
"user.gender": [male],
"user.age": [26],
"user.name.full": [john, smith],
"user.name.first": [john],
"user.name.last": [smith]
}
但是这种如果是对象数组的情况,数据相关性就会丢失了,如下如果使用默认的映射规则,"comments"会被映射为object,这样的结构就没办法区分,所以ES提供了nested字段类型,作为嵌套对象数组类型的区分,即会为每一个对象都对应一个独立的文档
{
"title": "Nest eggs",
"body": "Making your money work...",
"tags": [ "cash", "shares" ],
"comments": [
{
"name": "John Smith",
"comment": "Great article",
"age": 28,
"stars": 4,
"date": "2014-09-01"
},
{
"name": "Alice White",
"comment": "More like this please",
"age": 31,
"stars": 5,
"date": "2014-10-22"
}
]
}
#默认以object类型映射
{
"title": [ eggs, nest ],
"body": [ making, money, work, your ],
"tags": [ cash, shares ],
"comments.name": [ alice, john, smith, white ],
"comments.comment": [ article, great, like, more, please, this ],
"comments.age": [ 28, 31 ],
"comments.stars": [ 4, 5 ],
"comments.date": [ 2014-09-01, 2014-10-22 ]
}
#以nested类型映射
{
"comments.name": [ john, smith ],
"comments.comment": [ article, great ],
"comments.age": [ 28 ],
"comments.stars": [ 4 ],
"comments.date": [ 2014-09-01 ]
}
{
"comments.name": [ alice, white ],
"comments.comment": [ like, more, please, this ],
"comments.age": [ 31 ],
"comments.stars": [ 5 ],
"comments.date": [ 2014-10-22 ]
}
{
"title": [ eggs, nest ],
"body": [ making, money, work, your ],
"tags": [ cash, shares ]
}
参考
https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.5.4.zip
https://www.elastic.co/guide/cn/elasticsearch/guide/current/combining-filters.html
https://www.cnblogs.com/Transkai/p/11051869.html
https://www.elastic.co/guide/cn/elasticsearch/guide/cn/getting-started.html
https://es.xiaoleilu.com/030_Data/30_Create.html
https://www.cnblogs.com/gangle/p/9328257.html
http://localhost:9200/
java api聚合操作
https://blog.csdn.net/fly910905/article/details/81487269
https://blog.csdn.net/comeonyangzi/article/details/80597974
https://blog.csdn.net/majun_guang/article/details/81103623