重庆幸运农场中奖金额|重庆幸运农场官网
MyException - 我的異常網
當前位置:我的異常網» 搜索引擎 » 實時搜索引擎Elasticsearch(五)——Java API的使用

實時搜索引擎Elasticsearch(五)——Java API的使用

www.h0f1.com  網友分享于:2013-05-13  瀏覽:0次
實時搜索引擎Elasticsearch(5)——Java API的使用

介紹了使用Rest方式調用ES的聚合API。Rest API使用了HTTP協議,按理來說,可以直接使用類似HttpClient的工具直接調用Rest API。雖然筆者并沒有嘗試過,但稍微想想一下就知道這種方法是可行的。這種方法主要有下面幾個弊端:

  1. 需要開啟ES的Http服務和端口。ES提供的Http服務功能非常全面,沒有提供權限控制,防護也比較脆弱。一旦遭到破解,則數據面臨極大的風險。所以,建議在生產中關閉Http服務,或者自己增加一層代理來實現權限控制。
  2. 調用比較困難。Rest API的核心是url和post數據,url直接需傳入字符串,這樣就不能使用IDE的查錯功能。需要記憶的東西太多,不確定時就要去查API,影響開發效率。
  3. Http協議的一大特點是無連接性。也就是每一次請求都需要建立新的連接,我們知道tcp連接是比較耗時的過程。從性能的角度來說,直接使用Rest API也是不合適的。

ES所提供的Http服務適合用作集群狀態和數據的監控,而不適合直接用于數據操作。ES提供了多種語言(包括JavaPythonPHP、Ruby等)版本的Client API,可以使用這些Client API編程實現數據操作功能。作為一個Java語言編程者,本文主要介紹使用Java版本的Client來操作數據。使用Java API需要依賴ES所提供的jar包,我們使用maven來下載所需的依賴包,maven依賴定義如下:

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>1.5.0</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

version表示依賴包的版本,可以輸入任意存在的版本,本文的示例中使用1.5.0版的API。注意,建議API的版本與ES集群所使用的版本保持一致,以免出現因版本不一致而導致的沖突。

本文的主要內容包括:

  1. 介紹兩類Client,解釋它們的之間的差異;
  2. 使用Client進行index、document和聚合相關的操作。

1. Client

ES中所有的Java API調用都要使用Client對象,ES為API調用者提供了兩類Client對象:NodeClient和TransportClient。下面來講講這兩類Client的差異和使用場景。

1.1 NodeClient

NodeClient是一種嵌入式節點客戶端。它首先在客戶端啟動一個節點(Node),并加入同名集群內。這個節點可以保存數據,并且數據能夠被索引。然后從這個節點中獲取Client,這類Client就是NodeClient。NodeClient無需指明ES服務端的地址,操作的數據位于啟動的節點所在的集群中。下面是獲得NodeClient的代碼:

import org.elasticsearch.client.Client;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.node.Node;
import static org.elasticsearch.node.NodeBuilder.nodeBuilder;

public class MyNodeClient {

    public static void main(String[] args) {
        // 啟動一個本地節點,并加入子網內的ES集群
        Node node = nodeBuilder()
                    .clusterName("elasticsearch") // 要加入的集群名為elasticsearch
                    // .client(true) //如果設置為true,則該節點不會保存數據
                    .data(true) // 本嵌入式節點可以保存數據
                    .node(); // 構建并啟動本節點

        // 獲得一個Client對象,該對象可以對子網內的“elasticsearch”集群進行相關操作。
        Client nodeClient = node.client();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

運行這段代碼之后,可以看到工程中新增了一個data文件夾,這是因為data(true)將Node設置為可以存放數據的節點,數據正是放在了data文件夾下。

新增加的data文件夾

NodeClient適合用作單元或集成測試,而不適合用于生產環境。

1.2 TransportClient

TransportClient連接遠端的ES集群,其本身并不會加入集群。創建TransportClient的代碼如下:

import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;

import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;

public class MyTransportClient {

    public static void main(String[] args) {
        // 配置信息
        Settings esSetting = settingsBuilder()
                                .put("cluster.name", "elasticsearch")
                                .build();
        TransportClient transportClient = new TransportClient(esSetting);

        // 添加連接地址
        TransportAddress address = new InetSocketTransportAddress("192.168.1.110", 9300);
        TransportAddress address2 = new InetSocketTransportAddress("192.168.1.111", 9300);
        transportClient.addTransportAddress(address);
        transportClient.addTransportAddress(address2);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

TransportClient適合用于生產環境中。

2. Index操作

本小節介紹如果使用Java API創建和刪除索引。

2.1 創建索引

廢話先不說,上代碼先。下面的方法創建一個索引,并同時創建一個mapping。mapping可以傳入符合格式要求的json字符串。一般情況下,我們可以使用下面的方式來生成所需的json字符串。

  1. 手動拼接json字符串
  2. 使用類似jackson的工具將對象轉換為相應的json字符串
  3. 使用ES內置的XContentFactory.jsonBuilder()來創建json字符串。

本文的示例中均使用ES自帶的XContentFactory.jsonBuilder()來構建json字符串。

/**
 * 創建一個索引
 * @param indexName 索引名
 */
public void createIndex(String indexName) {
    try {
        CreateIndexResponse indexResponse = this.client
                                .admin()
                                .indices()
                                .prepareCreate(indexName)
                                .get();

        System.out.println(indexResponse.isAcknowledged()); // true表示創建成功
    } catch (ElasticsearchException e) {
        e.printStackTrace();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

如果需要再索引上新建mapping,可通過下面的代碼來實現。

/**
 * 給索引增加mapping。
 * @param index 索引名
 * @param type mapping所對應的type
 */
public void addMapping(String index, String type) {
    try {
        // 使用XContentBuilder創建Mapping
        XContentBuilder builder = 
            XContentFactory.jsonBuilder()
                            .startObject()
                                .field("properties")
                                    .startObject()
                                        .field("name")
                                            .startObject()
                                                .field("index", "not_analyzed")
                                                .field("type", "string")
                                            .endObject()
                                        .field("age")
                                            .startObject()
                                                .field("index", "not_analyzed")
                                                .field("type", "integer")
                                            .endObject()
                                    .endObject()
                            .endObject();
        System.out.println(builder.string());           
        PutMappingRequest mappingRequest = Requests.putMappingRequest(index).source(builder).type(type);
                this.client.admin().indices().putMapping(mappingRequest).actionGet();
    } catch (ElasticsearchException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

3.1 刪除索引

/**
 * 刪除索引
 * @param index 要刪除的索引名
 */
public void deleteIndex(String index) {
    DeleteIndexResponse deleteIndexResponse = 
        this.client
            .admin()
            .indices()
            .prepareDelete(index)
            .get();
    System.out.println(deleteIndexResponse.isAcknowledged()); // true表示成功
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

3. 文檔CURD操作

增刪改查是數據的基本操作,同時也是使用頻率最高的一類操作。本小節介紹使用Java API來實現document的增刪改查。

3.1 新增文檔

/**
 * 創建一個文檔
 * @param index index
 * @param type type
 */
public void createDoc(String index, String type) {

    try {
        // 使用XContentBuilder創建一個doc source
        XContentBuilder builder = 
            XContentFactory.jsonBuilder()
                            .startObject()
                                .field("name", "zhangsan")
                                .field("age", "lisi")
                            .endObject();

        IndexResponse indexResponse = this.client
                                        .prepareIndex()
                                        .setIndex(index)
                                        .setType(type)
                                        // .setId(id) // 如果沒有設置id,則ES會自動生成一個id
                                        .setSource(builder.string())
                                        .get();
        System.out.println(indexResponse.isCreated());
    } catch (ElasticsearchException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

3.2 更新文檔

/**
 * 更新文檔
 * @param index
 * @param type
 * @param id
 */
public void updateDoc(String index, String type, String id) {
    try {
        XContentBuilder builder = 
            XContentFactory.jsonBuilder()
                            .startObject()
                                .field("name", "lisi")
                                .field("age", 12)
                            .endObject();

        UpdateResponse updateResponse = 
            this.client
                .prepareUpdate()
                .setIndex(index)
                .setType(type)
                .setId(id)
                .setDoc(builder.string())
                .get();
        System.out.println(updateResponse.isCreated()); // true表示成功
    } catch (ElasticsearchException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

注意,id參數必須是確定存在的id值,否則會拋出document missing的異常。

3.3 查詢文檔

查詢文檔可以是根據id查詢,也可以是根據復雜的查詢條件查詢。根據id的get查詢代碼如下。

/**
 * 根據ID查詢一條數據記錄。
 * @param id 要查詢數據的ID。
 * @return 返回查詢出來的記錄對象的json字符串。
 */
public String get(String index, String type, String id) {
    GetResponse getResponse = this.client
                                .prepareGet()   // 準備進行get操作,此時還有真正地執行get操作。(與直接get的區別)
                                .setIndex(index)  // 要查詢的
                                .setType(type)
                                .setId(id)
                                .get();
    return getResponse.getSourceAsString();
}
````

基于復雜查詢條件的示例代碼如下。





<div class="se-preview-section-delimiter"></div>

```java
/**
 * 使用filter方式查詢數據。
 * @param index 數據所在的索引名
 * @param type 數據所在的type
 * @return 
 */
public List<String> queryByFilter(String index, String type) {

    // 查詢名為zhangsan的數據
    FilterBuilder filterBuilder = FilterBuilders.termFilter("name", "zhangsan");
    SearchResponse searchResponse = 
        this.client
            .prepareSearch()  
            .setIndices(index)
            .setTypes(type)
            .setPostFilter(filterBuilder)
            .get();

    List<String> docList = new ArrayList<String>();
    SearchHits searchHits = searchResponse.getHits();
    for (SearchHit hit : searchHits) {
        docList.add(hit.getSourceAsString());
    }
    return docList;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

3.4 刪除文檔

下面的代碼刪除指定id的文檔。

/**
 * 刪除一條數據
 * @param index
 * @param type
 * @param id
 */
public void deleteDoc(String index, String type, String id) {
    DeleteResponse deleteResponse  = this.client
            .prepareDelete()  
            .setIndex(index)
            .setType(type)
            .setId(id)
            .get();
    System.out.println(deleteResponse.isFound()); // true表示成功
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

根據復雜的查詢條件來刪除文檔。

/**
 * 根據查詢條件刪除文檔。
 */
public void deleteByQuery(String index, String type) {
    try {
        QueryBuilder queryBuilder = QueryBuilders.termQuery("name", "zhangsan");
        DeleteByQueryResponse deleteByQueryResponse = this.client
                .prepareDeleteByQuery(index)
                .setTypes(type)
                .setQuery(queryBuilder)
                .get();
    } catch (ElasticsearchException e) {
        e.printStackTrace();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

4. 聚合操作

聚合操作的API稍微比較復雜一點,本文僅以min聚合的示例來說明聚合API的調用方式,其他的聚合API調用步驟類似。

/**
 * 使用min聚合查詢某個字段上最小的值。
 * @param index
 * @param type
 */
public void min(String index, String type) {
    SearchResponse response = this.client
                            .prepareSearch(index)
                            .addAggregation(AggregationBuilders.min("min").field("age"))
                            .get();

    InternalMin min = response.getAggregations().get("min");
    System.out.println(min.getValue());
}

文章評論

不懂技術不要對懂技術的人說這很容易實現
不懂技術不要對懂技術的人說這很容易實現
“懶”出效率是程序員的美德
“懶”出效率是程序員的美德
Web開發者需具備的8個好習慣
Web開發者需具備的8個好習慣
Java 與 .NET 的平臺發展之爭
Java 與 .NET 的平臺發展之爭
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
旅行,寫作,編程
旅行,寫作,編程
漫畫:程序員的工作
漫畫:程序員的工作
中美印日四國程序員比較
中美印日四國程序員比較
2013年美國開發者薪資調查報告
2013年美國開發者薪資調查報告
團隊中“技術大拿”并非越多越好
團隊中“技術大拿”并非越多越好
為啥Android手機總會越用越慢?
為啥Android手機總會越用越慢?
十大編程算法助程序員走上高手之路
十大編程算法助程序員走上高手之路
程序員和編碼員之間的區別
程序員和編碼員之間的區別
聊聊HTTPS和SSL/TLS協議
聊聊HTTPS和SSL/TLS協議
60個開發者不容錯過的免費資源庫
60個開發者不容錯過的免費資源庫
什么才是優秀的用戶界面設計
什么才是優秀的用戶界面設計
為什么程序員都是夜貓子
為什么程序員都是夜貓子
編程語言是女人
編程語言是女人
程序員的鄙視鏈
程序員的鄙視鏈
程序員的一天:一寸光陰一寸金
程序員的一天:一寸光陰一寸金
每天工作4小時的程序員
每天工作4小時的程序員
我跳槽是因為他們的顯示器更大
我跳槽是因為他們的顯示器更大
初級 vs 高級開發者 哪個性價比更高?
初級 vs 高級開發者 哪個性價比更高?
如何區分一個程序員是“老手“還是“新手“?
如何區分一個程序員是“老手“還是“新手“?
Java程序員必看電影
Java程序員必看電影
總結2014中國互聯網十大段子
總結2014中國互聯網十大段子
鮮為人知的編程真相
鮮為人知的編程真相
當下全球最炙手可熱的八位少年創業者
當下全球最炙手可熱的八位少年創業者
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
一個程序員的時間管理
一個程序員的時間管理
5款最佳正則表達式編輯調試器
5款最佳正則表達式編輯調試器
10個幫程序員減壓放松的網站
10個幫程序員減壓放松的網站
我的丈夫是個程序員
我的丈夫是個程序員
如何成為一名黑客
如何成為一名黑客
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
寫給自己也寫給你 自己到底該何去何從
寫給自己也寫給你 自己到底該何去何從
 程序員的樣子
程序員的樣子
程序員應該關注的一些事兒
程序員應該關注的一些事兒
老程序員的下場
老程序員的下場
親愛的項目經理,我恨你
親愛的項目經理,我恨你
Google倫敦新總部 猶如星級莊園
Google倫敦新總部 猶如星級莊園
代碼女神橫空出世
代碼女神橫空出世
程序員都該閱讀的書
程序員都該閱讀的書
程序員周末都喜歡做什么?
程序員周末都喜歡做什么?
那些爭議最大的編程觀點
那些爭議最大的編程觀點
程序員最害怕的5件事 你中招了嗎?
程序員最害怕的5件事 你中招了嗎?
看13位CEO、創始人和高管如何提高工作效率
看13位CEO、創始人和高管如何提高工作效率
那些性感的讓人尖叫的程序員
那些性感的讓人尖叫的程序員
Web開發人員為什么越來越懶了?
Web開發人員為什么越來越懶了?
軟件開發程序錯誤異常ExceptionCopyright © 2009-2015 MyException 版權所有
重庆幸运农场中奖金额