1. 程式人生 > >elasticsearch api示例

elasticsearch api示例

工作中使用到elasticsearch,整理了一下常用的api示例,僅供參考!!!

package com.jd.jr.poi.utils;

import com.jd.jr.poi.constant.Constants;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.*;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.metrics.avg.Avg;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import java.math.BigDecimal;
import java.util.*;


/**
 * BoolQuery:進行搜尋的程式碼,適用於複雜搜尋邏輯
 * must:文件必須完全匹配條件
 * mustNot:文件必須不匹配條件
 * should:should下面會帶一個以上的條件,至少滿足一個條件,這個文件就符合should
 * termQuery:完全匹配
 * termsQuery:一次匹配多個值
 * matchQuery:單個匹配, field不支援萬用字元, 字首具高階特性
 * matchPhraseQuery 必須所有term都在doc field中出現,而且距離在slop限定範圍內才能匹配上,可指定slot值,預設設定每個分詞之間的間隔為0
 * multiMatchQuery:匹配多個欄位, field有萬用字元忒行
 * matchAllQuery:匹配所有檔案
 * filter:過濾出想要的檔案,不是過濾掉檔案
 */
public class EsUtil implements Constants {

    /**
     * 正則過濾檔案
     * @param esClient
     * @param index
     * @param type
     */
    public void regex(Client esClient,String index,String type){
        QueryBuilder qb2 = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("city","北京")).mustNot(QueryBuilders.regexpQuery("district", ".*(海|澱).*"));
        SearchResponse searchResponse =esClient.prepareSearch(index).setQuery(qb2).execute().actionGet();
        LoggerUtil.info("regex-response:{}", JsonUtil.toJSON(searchResponse));
    }

    /**
     * 獲取平均值
     * @param esClient
     * @param index
     * @param type
     * @param qb 條件
     * @param field 對應的屬性欄位
     */
    public void getAvgPr(Client esClient,String index,String type,QueryBuilder qb, String field){
        AggregationBuilder termsBuilder = AggregationBuilders.avg("avg").field(field);
        SearchRequestBuilder sv=esClient.prepareSearch(index).setTypes(type).setQuery(qb).addAggregation(termsBuilder);
        SearchResponse response=  sv.execute().actionGet();
        Avg valueCount= response.getAggregations().get("avg");
        int intVal = ParserUtil.douToInt(valueCount.getValue(),0, BigDecimal.ROUND_UP);
        LoggerUtil.info("平均值,value:{}",intVal);
    }

    /**
     * 查詢座標1到座標2矩形範圍內,的使用者有那些

     */
    public void testGetNearbyPeople(Client esClient,String index,String type, double lat1, double lon1, double lat2,double lon2) {
        SearchRequestBuilder srb = esClient.prepareSearch(index).setTypes(type);
        SearchResponse searchResponse = srb.setQuery(QueryBuilders.geoBoundingBoxQuery("location").setCorners(lat1, lon1, lat2, lon2)).get();
        for (SearchHit searchHit : searchResponse.getHits().getHits()) {
            LoggerUtil.info("getJuxing-response:{}", JsonUtil.toJSON(searchHit.getSourceAsString()));
        }
    }

    /**
     * 是否存在
     * @param esClient
     * @param index
     * @param type
     */
    public void isHaving(Client esClient,String index,String type){
        //組裝ES查詢條件
        QueryBuilder qb =qb = QueryBuilders.boolQuery().must(QueryBuilders.matchPhraseQuery("id","0185d356e02d4214e82888b"));
        //search_type設定為query_and_fetch的聚合查詢不會導致記憶體溢位,而預設的query_then_fetch則會記憶體溢位
        SearchResponse poiResponse=esClient.prepareSearch(index).setTypes(type).setQuery(qb).setSearchType(SearchType.QUERY_AND_FETCH).execute().actionGet();
        LoggerUtil.info("poiResponse1:{}",JsonUtil.toJSON(poiResponse));
    }

    /**
     * 獲取座標 附近1000米的資訊
     *
     */
    public void getNearbyPosition(Client esClient,String index,String type) {

        SearchRequestBuilder srb = esClient.prepareSearch(index).setTypes(type);
        srb.setFrom(0).setSize(1000);// 1000人
        GeoDistanceQueryBuilder location1 = QueryBuilders.geoDistanceQuery("location").point(40.372486, 40.372486).distance(5000, DistanceUnit.MILES);
        srb.setPostFilter(location1);

        // 獲取距離多少公里 這個才是獲取點與點之間的距離的
        GeoDistanceSortBuilder sort = SortBuilders.geoDistanceSort("location", 40.372486, 40.372486);
        sort.unit(DistanceUnit.MILES);
        sort.order(SortOrder.ASC);
        sort.point(40.372486, 40.372486);
        srb.addSort(sort);
        SearchResponse searchResponse = srb.execute().actionGet();
        LoggerUtil.info("getNearbyPosition-response:{}",JsonUtil.toJSON(searchResponse));
        SearchHits hits = searchResponse.getHits();
        SearchHit[] searchHists = hits.getHits();
        // 搜尋耗時
        Float usetime = searchResponse.getTookInMillis() / 1000f;
        LoggerUtil.info("getNearbyPosition-response:{}","座標附近有(" + hits.getTotalHits() + "個),耗時(" + usetime + "秒):");
        for (SearchHit hit : searchHists) {
            String name = (String) hit.getSource().get("district");
            GeoPointLL location_ = JsonUtil.toBean(JsonUtil.toJSON(hit.getSource().get("location")),GeoPointLL.class);
            // 獲取距離值,並保留兩位小數點
            BigDecimal geoDis = new BigDecimal((Double) hit.getSortValues()[0]);
            Map<String, Object> hitMap = hit.getSource();
            // 在建立MAPPING的時候,屬性名的不可為geoDistance。
            hitMap.put("geoDistance", geoDis.setScale(0, BigDecimal.ROUND_HALF_DOWN));
            LoggerUtil.info("getNearbyPosition-location:{}",name + "的座標:" + JsonUtil.toJSON(location_) + "距離座標" + hit.getSource().get("geoDistance") + DistanceUnit.METERS.toString());
        }

    }

    /**
     * 地理位置
     * 不用org.elasticsearch.common.geo.GeoPoint,會拋org.elasticsearch.ElasticsearchParseException:field必須是lat / lon或geohash
     */
    class GeoPointLL {

        double lat, lon;

        public GeoPointLL() {
        }

        public GeoPointLL(double lat, double lon) {
            this.lat = lat;
            this.lon = lon;
        }

        public double getLat() {
            return lat;
        }

        public void setLat(double lat) {
            this.lat = lat;
        }

        public double getLon() {
            return lon;
        }

        public void setLon(double lon) {
            this.lon = lon;
        }
    }

    /**
     * 多邊形查詢
     */
    public void polygonQuery(Client esClient,String index,String type) {
        List<GeoPoint> points=new ArrayList<GeoPoint>();
        points.add(new GeoPoint(42, -72));
        points.add(new GeoPoint(39, 117));
        points.add(new GeoPoint(40, 117));
        SearchResponse response = esClient.prepareSearch(index).setTypes(type).setQuery(QueryBuilders.geoPolygonQuery("location",points)).get();
        LoggerUtil.info("polygonQuery:{}",JsonUtil.toJSON(response));
    }

    /**
     * 寫入
     * @param esClient
     * @param index
     * @param type
     * @param map 寫入資料
     */
    public void writeES(Client esClient,String index,String type,Map<String, Object> map){
        LoggerUtil.info("prepareIndex-request:{}",JsonUtil.toJSON(map));
        IndexResponse response = esClient.prepareIndex(index, type).setSource(map).get();
        LoggerUtil.info("prepareIndex-response:{}",JsonUtil.toJSON(response));

    }


    /**
     * 更新
     * @param esClient
     * @param index
     * @param type
     * @param id 當前資料的id主鍵,searchHit.getId()
     */
    private void upSetES(Client esClient, String index, String type, String id){
        try {
            UpdateRequest updateRequest = new UpdateRequest(index, type, id);
            updateRequest.doc(XContentFactory.jsonBuilder().startObject()
                    .field("name", "Joe Smith")
                    .endObject());
            esClient.update(updateRequest).actionGet();
        }catch (Exception e){
            LoggerUtil.error("upSetES,呼叫失敗", e.getMessage(), e);
        }
    }

    /**
     * 分頁獲取
     * @param esClient
     * @param index
     * @param type
     * @throws Exception
     */
    private void getDataByPage(Client esClient, String index, String type){
        //初始化物件
        SearchHits hits = null;SearchHit[] hitArray = null;
        try {
            //組裝ES查詢條件
            QueryBuilder qb = QueryBuilders.boolQuery().must(QueryBuilders.matchPhraseQuery("name","Joe Smith"));
            /**
             * 查詢建立
             * setSearchType, 執行檢索的類別
             * setSize,需要查詢出多少條結果;
             * setFrom,從哪一個Score開始查;
             * 注:from*size要小於10000
             * addSort,設定排序;
             * setScroll,設定滾動的時間;
             */
            SearchResponse poiResponse=esClient.prepareSearch(esIndexName).setTypes(esTypeName)
                    .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                    .setScroll(TimeValue.timeValueMinutes(1))
                    .setQuery(qb)
                    .setSize(esPageNum).execute().actionGet();

            while (true) {
                hits = poiResponse.getHits();
                hitArray = hits.getHits();
                for (SearchHit searchHit : hitArray) {
                    LoggerUtil.info("getDataByPage-id:{}",searchHit.getId());
                }
                poiResponse = esClient.prepareSearchScroll(poiResponse.getScrollId()).setScroll(TimeValue.timeValueMinutes(10)).execute().actionGet();
                if (poiResponse.getHits().getHits().length == 0) {
                    break;
                }
                //初始化物件
                hits=null;hitArray=null;
            }
            /**
             * 處理結束後,記得clean scroll,清除滾動ID
             */
            clearScroll(esClient,poiResponse.getScrollId());

            //初始化物件
            qb=null;poiResponse=null;
        } catch (Exception e) {
            LoggerUtil.error("getDataByPage-getPoiData,獲取POI資料失敗", e.getMessage(), e);
        }
    }

    /**
     * 清除滾動ID
     * 雖然當滾動有效時間已過,搜尋上下文(Search Context)會自動被清除,但是一值保持滾動代價也是很大的,所以當我們不在使用滾動時要儘快使用Clear-Scroll API進行清除。
     * @param scrollId
     * @return
     */
    public boolean clearScroll(Client esClient,String scrollId){
        ClearScrollRequestBuilder clearScrollRequestBuilder = esClient.prepareClearScroll();
        clearScrollRequestBuilder.addScrollId(scrollId);
        ClearScrollResponse response = clearScrollRequestBuilder.get();
        LoggerUtil.info("clearScroll,處理結束後,清除滾動ID,result;{}",JsonUtil.toJSON(response));
        return response.isSucceeded();
    }
}