elasticsearch提供DSL(domain specific language)查询,就是以json格式定义查询条件实现复杂条件查询。
DSL查询分为俩大类:
叶子查询:一般是在特定的字段里查询特定值,属于简单查询,很少单独使用。
复合查询:以逻辑方式组合多个叶子查询后者更改叶子查询的行为方式。
我们还可以对查询结果做进一步的处理,博包括:排序、分页、高亮、聚合等等。
叶子查询: 叶子查询进一步细分有
全文检索查询:利用分词器对用户输入内容分词,然后去词条列表中匹配。
精确查询:不对用户输入内容分词,直接精确匹配,一般是查找keyword、数值、日期、布尔类型等等。
地理查询:用于搜索地理位置。
代码实现: 我已经把我数据库的信息存储一份到elasticSearch中了,各位在进行下面操作时不忘了把自己数据库的数据存储一份到elasticsearch。 在写代码时,我会先告诉大家在elasticsearch中的代码实现,然后根据elasticsearch的代码去实现Java代码。
全文检索查询: match(单字段查询) 和 multi_match(多字段查询)
注意:es中查询数据,最多查询到10000条,但控制台只会显示出10条。所以要注意看到查询结果中显示查询到数据10000条时,很可能符合条件的数据不止10000条。
#match查询所有
GET /items/_search
{"query": {"match": {"name": "脱脂牛奶"}}
}
控制台返回:
我来说一下返回数据中最外层的数据是什么意思: took 表示查询话费的时间;timed_out表示是否超时;_shared 是分片情况;hits是命中情况,就是符合条件的基本信息。
我们主要看hits命中信息: 其中total中的vaule和relation分别是查询到的信息数量 和 查询方式equals。 max_score 表示最大相关性得分,es有个底层算法可以帮我们算出每条信息与我们搜索内容的相关性。然后后面又是一个hits,这个内层的hits就是我们查询到的每条数据的详细信息,_index表示在哪个索引库中进行的操作;_type表示对什么进行的操作,_source就是查到的每条数据了。
下面我们开始写相应的Java代码:
首先我们要初始化对es操作的客户端:
private RestHighLevelClient client;@BeforeEachvoid setUp() {client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://localhost:9200")));}@AfterEachvoid tearDown() throws IOException {if (client != null) {client.close();}}
然后我们就可以用client对es进行各种操作了。
//查询单、多字段@Testvoid testMatch() throws IOException {SearchRequest request = new SearchRequest("items");//索引库名//单字段request.source().query(QueryBuilders.matchQuery("name", "脱脂牛奶"));//多字段//request.source().query(QueryBuilders.multiMatchQuery("脱脂牛奶", "name", "category"));SearchResponse response = client.search(request, RequestOptions.DEFAULT);//解析数据SearchHits searchHits = response.getHits();SearchHit[] hits = searchHits.getHits();for (SearchHit hit : hits) {String source = hit.getSourceAsString();ItemDoc itemDoc = JSONUtil.toBean(source, ItemDoc.class);System.out.println("itemDoc: " + itemDoc);}}
首先创建一个用于发送请求的request对象,用于查询的用SearchRequest ;
单字段就是只对一个字段做查询,比如查询name字段中有 脱脂牛奶 的 ,格式是matchQuery("name", "脱脂牛奶")先写字段名,在写查询内容 。多字段就是对多个字段进行查询,格式是 multiMatchQuery("脱脂牛奶", "name", "category") 先写查询内容,在写n个字段名,就是查询name中有"脱脂牛奶"的或者category中有"脱脂牛奶"的。发送请求用client.search(...) 返回响应数据response。
然后就是解析数据:这个要根据我们在es中做查询时返回的数据格式:我们要的是内层的那个hits中的source中的数据。而我们获取的response是最外面的大括号,里面有 took,timed_out,shards,hits。所以要先获取外层hits:SearchHits searchHits = response.getHits();然后在获取内层hits:SearchHit[] hits = searchHits.getHits();最后获取source:String source = hit.getSourceAsString();这样我们就获得了查询的详细信息了。
精确查询:
//精确查询@Testvoid testTerm() throws IOException {SearchRequest request = new SearchRequest("items");request.source().query(QueryBuilders.termQuery("brand", "德亚"));SearchResponse response = client.search(request, RequestOptions.DEFAULT);//解析数据explainData(response);}//范围查询@Testvoid testRange() throws IOException {SearchRequest request = new SearchRequest("items");request.source().query(QueryBuilders.rangeQuery("price").gte(10000).lte(15000));SearchResponse response = client.search(request, RequestOptions.DEFAULT);explainData(response);}
接下来说复合查询:可分为俩类
第一类:基于逻辑运算组合叶子查询,例如bool;
第二类:基于某种算法修改查询时的文档相关性算分,从而改变文档排名。
bool查询: 是一个或多个查询子句的组合,组合方式有:
must:必须匹配每个子查询,类似“与”;should:选择性匹配子查询,类似“或”;
must_not:必须不匹配,不参与算法,类似“非” ;filter:必须匹配,不参与算法。
这里说的算法指的是计算该数据与搜索内容相关性的算法,像品牌、价格就不需要参与算法。
@Testvoid testBool() throws IOException {SearchRequest request = new SearchRequest("items");request.source().query(QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("name", "脱脂牛奶")).filter(QueryBuilders.termQuery("brand", "德亚")).filter(QueryBuilders.rangeQuery("price").lte(30000)));SearchResponse response = client.search(request, RequestOptions.DEFAULT);explainData(response);}
//我把解析数据的操作写成了一个方法
private void explainData(SearchResponse response) {SearchHits searchHits = response.getHits();TotalHits totalHits = searchHits.getTotalHits();System.out.println("total: " + totalHits);SearchHit[] hits = searchHits.getHits();for (SearchHit hit : hits) {String source = hit.getSourceAsString();ItemDoc itemDoc = JSONUtil.toBean(source, ItemDoc.class);Map<String, HighlightField> highlightFields = hit.getHighlightFields();if (highlightFields!=null&&!highlightFields.isEmpty()) {HighlightField name = highlightFields.get("name");if (name!=null){String hm = name.getFragments()[0].toString();itemDoc.setName(hm);}System.out.println("itemDoc: " + itemDoc);}}}