elasticsearch java使用

本文将介绍如何使用 java 调用 elasticsearch 的 api 。

1、获取client连接

package com.test.elasticsearch;

import java.net.InetAddress;
import java.net.UnknownHostException;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.junit.After;
import org.junit.Before;

/**
 * 抽象的Junit测试
 * 
 * @author xuwenjin
 */
public abstract class AbstractJunitTest {
    
    protected Logger logger = LogManager.getLogger(this.getClass());
    
    protected Client client;

    /**
     * 获取一个客户端
     */
    @SuppressWarnings("resource")
    @Before
    public void getClient() throws UnknownHostException {
        Settings settings = Settings.builder().put("cluster.name", "xwj").build();

        TransportAddress transportAddress = new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300);
        client = new PreBuiltTransportClient(settings).addTransportAddress(transportAddress);
    }

    /**
     * 关闭连接
     */
    @After
    public void close() {
        client.close();
    }
    
}

 

2、新增、删除索引

package com.test.elasticsearch;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequestBuilder;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequestBuilder;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.junit.Test;

/**
 * 索引操作测试
 * 
 * @author xuwenjin
 */
public class IndexTest extends AbstractJunitTest {

    /**
     * 判断是否存在该索引
     * 
     * @param indexName
     *            索引名称
     * @return
     */
    public boolean isIndexExists(String indexName) {
        IndicesExistsRequestBuilder builder = client.admin().indices().prepareExists(indexName);
        IndicesExistsResponse res = builder.get();
        return res.isExists();
    }

    /**
     * 5.*之后,把string字段设置为了过时字段,引入text,keyword字段
     * 
     * keyword:存储数据时候,不会分词建立索引
     * text:存储数据时候,会自动分词,并生成索引(这是很智能的,但在有些字段里面是没用的,所以对于有些字段使用text则浪费了空间)。
     *
     * 如果在添加分词器的字段上,把type设置为keyword,则创建索引会失败
     */
    public XContentBuilder getIndexSource() throws IOException {
        XContentBuilder source = XContentFactory.jsonBuilder().startObject().startObject("test_type2")
                .startObject("properties")
                // code字段
                .startObject("code").field("type", "text").field("index", true).field("fielddata", true).endObject()
                // 名称字段
                .startObject("name").field("type", "keyword").field("store", false).field("index", true).endObject()
                // 信息字段
                .startObject("info").field("type", "keyword").field("store", false).field("index", true).endObject()
                // 主要内容字段
                .startObject("content").field("type", "text").field("store", true).field("index", true).field("analyzer", "ik_max_word").endObject()
                .startObject("my_title").field("type", "keyword").field("store", true).field("index", true).endObject()
                .startObject("you_title").field("type", "keyword").field("store", true).field("index", true).endObject()
                .startObject("isDelete").field("type", "boolean").field("store", true).field("index", true).endObject()
                .startObject("age").field("type", "long").field("store", true).field("index", true).endObject()
                
                .endObject().endObject().endObject();
        return source;
    }

    /**
     * 创建索引
     */
    @Test
    public void createIndex() {
        try {
            if (isIndexExists("test_index2")) {
                logger.info("索引对象已经存在,无法创建!");
                return;
            }
            CreateIndexRequestBuilder builder = client.admin().indices().prepareCreate("test_index2");
            // 直接创建Map结构的setting
            Map<String, Object> settings = new HashMap<>();
            settings.put("number_of_shards", 5); // 分片数
            settings.put("number_of_replicas", 1); // 副本数
            settings.put("refresh_interval", "10s"); // 刷新间隔
            builder.setSettings(settings);

            builder.addMapping("test_type2", getIndexSource());

            CreateIndexResponse res = builder.get();
            logger.info(res.isAcknowledged() ? "索引创建成功!" : "索引创建失败!");
        } catch (Exception e) {
            logger.error("创建索引失败!", e);
        }
    }

    /**
     * 删除索引
     */
    @Test
    public void deleteIndex() {
        try {
            if (!isIndexExists("test_index2")) {
                logger.info("索引对象已经不存在,无法删除!");
                return;
            }
            DeleteIndexRequestBuilder builder = client.admin().indices().prepareDelete("test_index2");
            DeleteIndexResponse res = builder.get();
            logger.info(res.isAcknowledged() ? "删除索引成功!" : "删除索引失败!");
        } catch (Exception e) {
            logger.error("删除索引失败!", e);
        }
    }

}

执行createIndex方法之后,可以在elasticsearch-head中看到该索引被创建。

 

3、向ES中添加数据

package com.test.elasticsearch;

import java.util.HashMap;
import java.util.Map;

import org.junit.Test;

/**
 * 向ES中添加数据
 * 
 * @author xuwenjin
 */
public class AddDataTest extends AbstractJunitTest {

    // private static final String INDEX = "test_index1";
    // private static final String TYPE = "test_type1";
    private static final String INDEX2 = "test_index2";
    private static final String TYPE2 = "test_type2";

    @Test
    public void saveData() {
        try {
            Map<String, Object> source = new HashMap<String, Object>();
            source.put("code", "01");
            source.put("name", "科技");
            source.put("info", "中共十九大");
            source.put("content", "中共十九大");
            source.put("my_title", "我的标题12323abcd");
            source.put("you_title", "你的标题1efg");
            source.put("isDelete", true);
            source.put("age", 16);

            Map<String, Object> source2 = new HashMap<String, Object>();
            source2.put("code", "02");
            source2.put("name", "新闻");
            source2.put("info", "中国***");
            source2.put("content", "中国***");
            source2.put("my_title", "我的标题235325abcd");
            source2.put("you_title", "你的标题346565efg");
            source2.put("isDelete", false);
            source2.put("age", 17);

            Map<String, Object> source3 = new HashMap<String, Object>();
            source3.put("code", "03");
            source3.put("name", "科学技术");
            source3.put("info", "用友建筑大武汉");
            source3.put("content", "用友建筑大武汉");
            source3.put("my_title", "我的标题65845abcd");
            source3.put("you_title", "你的标题237678efg");
            source3.put("isDelete", false);
            source3.put("age", 18);

            Map<String, Object> source4 = new HashMap<String, Object>();
            source4.put("code", "04");
            source4.put("name", "快手视频");
            source4.put("info", "中国特色社会主义");
            source4.put("content", "中国特色社会主义");
            source4.put("my_title", "我的标题6789dfgf");
            source4.put("you_title", "你的标题67458sdfdf");
            source4.put("isDelete", true);
            source4.put("age", 19);

            Map<String, Object> source5 = new HashMap<String, Object>();
            source5.put("code", "05");
            source5.put("name", "科技视频");
            source5.put("info", "最美天安门");
            source5.put("content", "最美天安门");
            source5.put("my_title", "132445dfgdfg");
            source5.put("you_title", "32557fdgfg");
            source5.put("isDelete", true);
            source5.put("age", 20);

            Map<String, Object> source6 = new HashMap<String, Object>();
            source6.put("code", "06");
            source6.put("name", "最快的技术");
            source6.put("info", "美丽大武汉");
            source6.put("content", "美丽大武汉");
            source6.put("my_title", "356thjmkj345");
            source6.put("you_title", "4gfjgfjg4523");
            source6.put("isDelete", false);
            source6.put("age", 21);

            client.prepareIndex(INDEX2, TYPE2).setId("1").setSource(source).get();
            client.prepareIndex(INDEX2, TYPE2).setId("2").setSource(source2).get();
            client.prepareIndex(INDEX2, TYPE2).setId("3").setSource(source3).get();
            client.prepareIndex(INDEX2, TYPE2).setId("4").setSource(source4).get();
            client.prepareIndex(INDEX2, TYPE2).setId("5").setSource(source5).get();
            client.prepareIndex(INDEX2, TYPE2).setId("6").setSource(source6).get();

        } catch (Exception e) {
            logger.error("保存数据失败!", e);
        }
    }

}

 

4、简单查询、删除数据

package com.test.elasticsearch;

import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.junit.Test;

/**
 * 简单查询数据、删除数据
 * 
 * @author xuwenjin
 */
public class SimpleQueryTest extends AbstractJunitTest {

    private static final String INDEX = "test_index1"; // 索引
    private static final String TYPE = "test_type1"; // 类型

    @Test
    public void queryObject() {
        try {
            GetResponse res = client.prepareGet(INDEX, TYPE, "1").get();
            if (res.isExists()) {
                logger.info("根据ID查询到数据,主要内容:" + res.getSource().get("content"));
            } else {
                logger.info("根据ID未查询到数据!");
            }
        } catch (Exception e) {
            logger.error("根据ID查询记录失败!", e);
        }
    }

    @Test
    public void queryList() {
        try {
            String key = "***";
            QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(key, "name", "content");

            SearchResponse res = client.prepareSearch().setIndices(INDEX).setTypes(TYPE).setQuery(queryBuilder).get();

            logger.info("查询到的总记录个数为:" + res.getHits().getTotalHits());
            for (int i = 0; i < res.getHits().getTotalHits(); i++) {
                logger.info("" + (i + 1) + "条记录主要内容为:" + res.getHits().getAt(i).getSource().get("content"));
            }
        } catch (Exception e) {
            logger.error("查询列表失败!", e);
        }
    }

    @Test
    public void deleteData() {
        try {
            DeleteResponse res = client.prepareDelete(INDEX, TYPE, "1").get();

            logger.info("删除动作执行状态:" + res.status());
        } catch (Exception e) {
            logger.error("删除数据失败!", e);
        }
    }

}

 

5、复杂查询 

package com.test.elasticsearch;

import java.util.Map;

import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.junit.Test;

/**
 * 复杂查询,使用QueryBuilder进行bool查询
 * 
 * @author xuwenjin
 */
public class QueryBuilderTest extends AbstractJunitTest {

    private static final String INDEX2 = "test_index2";
    private static final String TYPE2 = "test_type2";

    public String text = "科技视频";

    /**
     * 单个精确值查找(termQuery)
     */
    @Test
    public void termQuery() {
        QueryBuilder queryBuilder = QueryBuilders.termQuery("code", "01");
        queryBuilder = QueryBuilders.termQuery("isDelete", true);
        queryBuilder = QueryBuilders.termQuery("my_title", "我的标题12323abcd");
        searchFunction(queryBuilder);
    }

    /**
     * 多个值精确查找(termsQuery)
     * 
     * 一个查询相匹配的多个value
     */
    @Test
    public void termsQuery() {
        QueryBuilder queryBuilder = QueryBuilders.termsQuery("code", "01", "03", "04");
        searchFunction(queryBuilder);
    }

    /**
     * 查询相匹配的文档在一个范围(rangeQuery)
     */
    @Test
    public void rangeQuery() {
        QueryBuilder queryBuilder = QueryBuilders
                .rangeQuery("code") // 查询code字段
                .from("02")
                .to("04")
                .includeLower(true) // 包括下界
                .includeUpper(false);// 不包括上界
        searchFunction(queryBuilder);
    }

    /**
     * 查询相匹配的文档在一个范围(prefixQuery)
     */
    @Test
    public void prefixQuery() {
        QueryBuilder queryBuilder = QueryBuilders.prefixQuery("my_title", "我的");
        searchFunction(queryBuilder);
    }

    /**
     * 通配符检索(wildcardQuery)
     * 
     * 值使用用通配符,常用于模糊查询
     * 
     * 匹配具有匹配通配符表达式( (not analyzed )的字段的文档。 支持的通配符: 
     *     *,它匹配任何字符序列(包括空字符序列)
     *     ?,它匹配任何单个字符。
     * 
     * 请注意,此查询可能很慢,因为它需要遍历多个术语。 为了防止非常慢的通配符查询,通配符不能以任何一个通配符*或?开头。
     */
    @Test
    public void wildcardQuery() {
        QueryBuilder queryBuilder = QueryBuilders.wildcardQuery("my_title", "*6789*");
        queryBuilder = QueryBuilders.wildcardQuery("my_title", "*345");
        queryBuilder = QueryBuilders.wildcardQuery("name", "?闻");
        searchFunction(queryBuilder);
    }

    /**
     * 正则表达式检索(regexpQuery) 不需要^、$
     */
    @Test
    public void regexpQuery() {
        QueryBuilder queryBuilder = QueryBuilders.regexpQuery("my_title", "我的.+f");
        searchFunction(queryBuilder);
    }

    /**
     * 使用模糊查询匹配文档查询(fuzzyQuery)
     */
    @Test
    public void fuzzyQuery() {
        QueryBuilder queryBuilder = QueryBuilders.fuzzyQuery("name", "科技");
        searchFunction(queryBuilder);
    }

    /**
     * 类型检索(typeQuery)
     * 
     * 查询该类型下的所有数据
     */
    @Test
    public void typeQuery() {
        QueryBuilder queryBuilder = QueryBuilders.typeQuery(TYPE2);
        searchFunction(queryBuilder);
    }

    /**
     * Ids检索, 返回指定id的全部信息 (idsQuery)
     * 
     * 在idsQuery(type)方法中,也可以指定具体的类型
     */
    @Test
    public void idsQuery() {
        QueryBuilder queryBuilder = QueryBuilders.idsQuery().addIds("1", "4", "10");
        searchFunction(queryBuilder);
    }

    /************************************************************ 全文检索 ************************************************************/

    /**
     * 单个匹配 (matchQuery)
     * 
     * 感觉跟termQuery效果一样
     */
    @Test
    public void matchQuery() {
        QueryBuilder queryBuilder = QueryBuilders.matchQuery("name", "科技");
        searchFunction(queryBuilder);
    }
    
    /**
     * 查询匹配所有文件 (matchAllQuery)
     */
    @Test
    public void matchAllQuery() {
        QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
        searchFunction(queryBuilder);
    }
    
    /**
     * 匹配多个字段, field可以使用通配符(multiMatchQuery)
     */
    @Test
    public void multiMatchQuery() {
        QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery("132445dfgdfg", "my_title", "name", "you_title");
        queryBuilder = QueryBuilders.multiMatchQuery("132445dfgdfg", "*title"); //字段使用通配符
        searchFunction(queryBuilder);
    }
    
    /**
     * 字符串检索(queryString)
     * 
     * 一个使用查询解析器解析其内容的查询。
     *  query_string查询提供了以简明的简写语法执行多匹配查询 multi_match queries ,布尔查询 bool queries ,提升得分 boosting ,模糊
     *  匹配 fuzzy matching ,通配符 wildcards ,正则表达式 regexp 和范围查询 range queries 的方式。
     *  
     *  支持参数达10几种
     */
    @Test
    public void queryString() {
        QueryBuilder queryBuilder = QueryBuilders.queryStringQuery("*技术");   //通配符查询
//        QueryBuilder queryBuilder = QueryBuilders.queryStringQuery("我的.+f");
        searchFunction(queryBuilder);
    }
    
    /**
     * must 相当于and,就是都满足 
     * should 相当于or,满足一个或多个 
     * must_not 都不满足
     */
    @Test
    public void testQueryBuilder2() {
        // "科技视频"分词的结果是"科技", "视频", "频"
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        // queryBuilder.must(QueryBuilders.wildcardQuery("name", "*科技*"));
        // queryBuilder.must(QueryBuilders.wildcardQuery("info", "*共*"));
        // queryBuilder.must(QueryBuilders.wildcardQuery("content", "*美丽*"));

        queryBuilder.should(QueryBuilders.wildcardQuery("name", "*科技*"));
        queryBuilder.should(QueryBuilders.wildcardQuery("info", "*共*"));
        queryBuilder.should(QueryBuilders.wildcardQuery("content", "*美丽*"));
        queryBuilder.minimumShouldMatch(2); // 最少匹配数

        // queryBuilder.mustNot(QueryBuilders.wildcardQuery("name", "*科技*"));
        // queryBuilder.mustNot(QueryBuilders.wildcardQuery("info", "*共*"));
        // queryBuilder.mustNot(QueryBuilders.wildcardQuery("content", "*美丽*"));
        searchFunction(queryBuilder);
    }

    /**
     * 查询遍历抽取
     * 
     * 查询结果是根据分值排序(从大到小)
     * 
     * @param queryBuilder
     */
    private void searchFunction(QueryBuilder queryBuilder) {
        SearchRequestBuilder requestBuilder = client.prepareSearch().setIndices(INDEX2).setTypes(TYPE2)
                .setScroll(new TimeValue(60000)).setQuery(queryBuilder);
        SearchResponse response = requestBuilder.setFrom(0).setSize(100).execute().actionGet();
        System.out.println("--------------查询结果:----------------------");
        for (SearchHit hit : response.getHits()) {
            System.out.println("分值:" + hit.getScore()); // 相关度
            Map<String, Object> map = hit.getSource();
            for (String sKey : map.keySet()) {
                System.out.println(sKey + ": " + map.get(sKey));
            }
            System.out.println("--------------");
        }
        System.out.println("-----------------------------------");
    }

}

本文的源码地址:https://github.com/xuwenjin/xwj_repo/tree/master/elasticsearch

参考资料:
  
解析Elasticsearch的SearchRequestBuilder的query类型 

  Elasticsearch检索分类深入详解—基础篇

  SearchRequestBuilder常用方法说明

  

 

posted @ 2018-04-11 18:02  仅此而已-远方  阅读(8831)  评论(1编辑  收藏  举报