可以通过两种方式来连接到elasticsearch(简称es)集群,第一种是通过在你的程序中创建一个嵌入es节点(Node),使之成为es集群的一部分,然后通过这个节点来与es集群通信。第二种方式是用TransportClient这个接口和es集群通信。
创建嵌入节点的方式如下:
import staticorg.elasticsearch.node.NodeBuilder.*;
//启动节点
Node node = nodeBuilder().node();
Client client = node.client();
//关闭节点
node.close();
当你启动一个节点,它会自动加入同网段的es集群,一个前提就是es的集群名(cluster.name)这个参数要设置一致。
默认的话启动一个节点,es集群会自动给它分配一些索引的分片,如果你想这个节点仅仅作为一个客户端而不去保存数据,你就可以设置把node.data设置成false或 node.client设置成true。下面是例子:
Node node =nodeBuilder().clusterName(clusterName).client(true).node();
还有一种情况是你并不想把节点加入集群,只想用它进行单元测试时,就要启动一个“本地”的es,这里“本地”指的是在jvm的级别下运行,即两个不同的es节点运行在同一个JVM中时会组成一个集群。它需要把节点的local参数设置成true,下面是例子:
Node node =nodeBuilder().local(true).node();
通过TransportClient这个接口,我们可以不启动节点就可以和es集群进行通信,它需要指定es集群中其中一台或多台机的ip地址和端口,例子如下:
Client client = new TransportClient()
.addTransportAddress(newInetSocketTransportAddress("host1", 9300))
.addTransportAddress(newInetSocketTransportAddress("host2", 9300));
client.close();
如果你需要更改集群名(默认是elasticsearch),需要如下设置:
Settings settings =ImmutableSettings.settingsBuilder()
.put("cluster.name","myClusterName").build();
Client client = newTransportClient(settings);
你可以设置client.transport.sniff为true来使客户端去嗅探整个集群的状态,把集群中其它机器的ip地址加到客户端中,这样做的好处是一般你不用手动设置集群里所有集群的ip到连接客户端,它会自动帮你添加,并且自动发现新加入集群的机器。代码实例如下:
Settings settings = ImmutableSettings.settingsBuilder()
.put("client.transport.sniff", true).build();
TransportClientclient = new TransportClient(settings);
{
"mappings":{
"properties":{
"title":{
"type":"string",
"store":"yes"
},
"description":{
"type":"string",
"index":"not_analyzed"
},
"price":{
"type":"double"
},
"onSale":{
"type":"boolean"
},
"type":{
"type":"integer"
},
"createDate":{
"type":"date"
}
}
}
}
接下来介绍通过请求添加mapping,下面为一个添加productIndex索引库的mapping的json格式请求。其中productIndex为索引类型,properties下面的为索引里面的字段,type为数据类型,store为是否存储,"index":"not_analyzed"为不对该字段进行分词。
{
"productIndex":{
"properties":{
"title":{
"type":"string",
"store":"yes"
},
"description":{
"type":"string",
"index":"not_analyzed"
},
"price":{
"type":"double"
},
"onSale":{
"type":"boolean"
},
"type":{
"type":"integer"
},
"createDate":{
"type":"date"
}
}
}
}
用java api调用的代码如下:
client.admin().indices().prepareCreate("productIndex").execute().actionGet();
put mapping:
XContentBuilder mapping = jsonBuilder()
.startObject()
.startObject("properties")
.startObject("title").field("type", "string").field("store", "yes").endObject()
.startObject("description").field("type", "string").field("index", "not_analyzed").endObject()
.startObject("price").field("type", "double").endObject()
.startObject("onSale").field("type", "boolean").endObject()
.startObject("type").field("type", "integer").endObject()
.startObject("createDate").field("type", "date").endObject()
.endObject()
.endObject();
PutMappingRequest mappingRequest = Requests.putMappingRequest("productIndex").type("productIndex").source(mapping);
client.admin().indices().putMapping(mappingRequest).actionGet();
XContentBuilder doc = jsonBuilder()
.startObject()
.field("title", "this is a title!")
.field("description", "descript what?")
.field("price", 100)
.field("onSale", true)
.field("type", 1)
.field("createDate", new Date())
.endObject();
client.prepareIndex("productIndex","productType").setSource(doc).execute().actionGet();
其中productIndex为索引库名,一个es集群中可以有多个索引库。productType为索引类型,是用来区分同索引库下不同类型的数据的,一个索引库下可以有多个索引类型。
DeleteResponse response = client.prepareDelete("twitter", "tweet", "1")
.execute()
.actionGet();
QueryBuilder query = QueryBuilders.fieldQuery("title", "query");
client.prepareDeleteByQuery("productIndex").setQuery(query).execute().actionGet();
设置线程
DeleteResponse response = client.prepareDelete("twitter", "tweet", "1")
.setOperationThreaded(false)
.execute()
.actionGet();
官方文档:
import static org.elasticsearch.index.query.FilterBuilders.*;
import static org.elasticsearch.index.query.QueryBuilders.*;
QueryBuilder qb1 = termQuery("name", "kimchy");
QueryBuilder qb2 = boolQuery()
.must(termQuery("content", "test1"))
.must(termQuery("content", "test4"))
.mustNot(termQuery("content", "test2"))
.should(termQuery("content", "test3"));
QueryBuilder qb3 = filteredQuery(
termQuery("name.first", "shay"),
rangeFilter("age")
.from(23)
.to(54)
.includeLower(true)
.includeUpper(false)
);
其中qb1构造了一个TermQuery,对name这个字段进行项搜索,项是最小的索引片段,这个查询对应lucene本身的TermQuery。 qb2构造了一个组合查询(BoolQuery),其对应lucene本身的BooleanQuery,可以通过must、should、mustNot方法对QueryBuilder进行组合,形成多条件查询。 qb3构造了一个过滤查询,就是在TermQuery的基础上添加一个过滤条件RangeFilter,这个范围过滤器将限制查询age字段大于等于23,小于等于54的结果。除了这三个,elasticsearch还支持很多种类的查询方式,迟点写个介绍。
SearchResponse response = client.prepareSearch("test")
.setQuery(query)
.setFrom(0).setSize(60).setExplain(true)
.execute()
.actionGet();
这句的意思是,查询test索引,查询条件为query,从第0条记录开始,最多返回60条记录。返回结果为SearchResponse,下面解析SearchResponse:
SearchHits hits = searchResponse.hits();
for (int i = 0; i < 60; i++) {
System.out.println(hits.getAt(i).getSource().get("field"));
}
获得SearchResponse中的SearchHits,然后hits.getAt(i).getSource().get("field")获得field字段的值。
import static org.elasticsearch.common.xcontent.XContentFactory.*;
BulkRequestBuilder bulkRequest = client.prepareBulk();
bulkRequest.add(client.prepareIndex("twitter", "tweet", "1")
.setSource(jsonBuilder()
.startObject()
.field("user", "kimchy")
.field("postDate", new Date())
.field("message", "trying out Elastic Search")
.endObject()
)
);
bulkRequest.add(client.prepareIndex("twitter", "tweet", "2")
.setSource(jsonBuilder()
.startObject()
.field("user", "kimchy")
.field("postDate", new Date())
.field("message", "another post")
.endObject()
)
);
BulkResponse bulkResponse = bulkRequest.execute().actionGet();
if (bulkResponse.hasFailures()) {
//处理错误
}
创建river方法:
$ curl -XPUT "localhost:9200/_river/mongodb/_meta" -d '
{
type: "mongodb",
mongodb: {
db: "test",
host: "localhost",
port: "27017",
collection: "testdb",
fields:"title,content",
gridfs: "true",
local_db_user: "admin",
local_db_password:"admin",
db_user: "user",
db_password:"password"
},
index: {
name: "test",
type: "type",
bulk_size: "1000",
bulk_timeout: "30"
}
}
db为同步的数据库名,
bulk_timeout 批量添加的超时时间
client.prepareIndex("_river", "testriver", "_meta")
.setSource(
jsonBuilder().startObject()
.field("type", "mongodb")
.startObject("mongodb")
.field("host","localhost")
.field("port",27017)
.field("db","testdb")
.field("collection","test")
.field("fields","title,content")
.field("db_user","user")
.field("db_password","password")
.field("local_db_user","admin")
.field("local_db_password","admin")
.endObject()
.startObject("index")
.field("name","test")
.field("type","test")
.field("bulk_size","1000")
.field("bulk_timeout","30")
.endObject()
.endObject()
).execute().actionGet();
本插件git地址:https://github.com/laigood/elasticsearch-river-mongodb
{
"more_like_this" : {
"fields" : ["title", "content"],
"like_text" : "text like this one",
}
}
其中:
MoreLikeThisRequestBuilder mlt = new MoreLikeThisRequestBuilder(client, "indexName", "indexType", "id");
mlt.setField("title");//匹配的字段
SearchResponse response = client.moreLikeThis(mlt.request()).actionGet();
这种是在查询与某个id的文档相似的文档。这个接口是直接在client那调用的,比较特殊。还有两种就是构造Query进行查询
MoreLikeThisQueryBuilder query = QueryBuilders.moreLikeThisQuery();
query.boost(1.0f).likeText("xxx").minTermFreq(10);
这里的boost、likeText方法完全和上面的参数对应的。下面这种就是把要匹配的字段作为参数传进来,参数和MoreLikeThisQueryBuilder是一样的。
MoreLikeThisFieldQueryBuilder query = QueryBuilders.moreLikeThisFieldQuery("fieldNmae");