【搜索】Elasticsearch全文搜索引擎的学习和使用

本文介绍了Elasticsearch,一个基于Lucene的分布式全文搜索引擎,强调了其在大数据时代的使用优势。文章详细讲解了Elasticsearch的安装、概念,如分片、复制,以及与Solr的对比。通过Java API展示了创建、修改、删除文档的操作,并提到了IKAnalyzer分析器在处理中文搜索中的作用。此外,还探讨了Elasticsearch的mapping映射配置和搜索功能的实现。

全文搜索引擎Elasticsearch

Elasticsearch简介

Elasticsearch是一个基于Lucene库的搜索引擎。它提供了一个分布式、支持多租户的全文搜索引擎,具有HTTP Web接口和无模式JSON文档。Elasticsearch是用Java开发的,并在Apache许可证下作为开源软件发布。官方客户端在Java.NETC#)、PHPPythonApache GroovyRuby和许多其他语言中都是可用的。[5]根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene。[6]

​ Elasticsearch是与名为Logstash的数据收集和日志解析引擎以及名为Kibana的分析和可视化平台一起开发的。这三个产品被设计成一个集成解决方案,称为“Elastic Stack”(以前称为“ELK stack”)。

​ Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。[5]”Elasticsearch是分布式的,这意味着索引可以被分成分片,每个分片可以有0个或多个副本。每个节点托管一个或多个分片,并充当协调器将操作委托给正确的分片。再平衡和路由是自动完成的。“[5]相关数据通常存储在同一个索引中,该索引由一个或多个主分片和零个或多个复制分片组成。一旦创建了索引,就不能更改主分片的数量。[7]

​ Elasticsearch使用Lucene,并试图通过JSON和Java API提供其所有特性。它支持facetting和percolating[8],如果新文档与注册查询匹配,这对于通知非常有用。

另一个特性称为“网关”,处理索引的长期持久性;例如,在服务器崩溃的情况下,可以从网关恢复索引。[9]Elasticsearch支持实时GET请求,适合作为NoSQL数据存储[10],但缺少分布式事务。——来自于维基百科


Elasticsearch简称es,概要:

  1. 是一个开源的高扩展的分布式全文检索引擎
  2. 近乎实时的存储、检索数据
  3. 本身扩展性好,支持集群,可以处理PB级别的数据,1024TB = 1PB
  4. Elasticsearch 在 Lucene 的基础上进行封装,实现了分布式搜索引擎
  5. es也使用 Java 开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API—HTTP/https来隐藏Lucene的复杂性;而restful风格遵循的是 http/https 协议
  6. es是一个 java 项目


为什么使用Elasticsearch?

原因:

​ 随着数据量越来越大,作为 Lucene 也感到吃力,将所有的数据分析后存放到一个索引库中,造成性能的降低。而 Elasticsearch 支持集群和分布式,很好的解决了这一问题,而解决这一问题的根本是 “分片”。

分片:当数据大时,不仅存储会降低效率,而且一旦数据丢失那么后果是很严重的。而 es 中提供了分片的概念,它将数据均衡的分配(使用“一致性Hash”)提高了性能。并且其分片还有一个复制的功能,这个功能是给主分片做一个备份,保证当主分片出问题时,备份会将其修复,备份也成为 副本。而副本并不做搜索的作用!

注意:分片的作用在单节点下并没什么用处,主要作用在集群环境中。在集群环境中,主分片和副本都会散布在各节点中,并且是均衡分配。还有一个注意事项就是 主分片和副本不可能在同一节点上!


Elasticsearch 与Solr的对比

  1. Solr 利用 zookeoper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能;
  2. Solr 支持更多格式的数据,而 Elasticsearch 仅支持json文件格式;
  3. Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多有第三方插件提供;
  4. Solr 在传统的搜索应用中表现好于 Elasticsearch,但在处理实时搜索应用时效率明显低于 Elasticsearch 当单纯的对已有数据进行搜索时,Solr更快,当实时建立索引时, Solr会产生io阻塞,查询性能较差, Elasticsearch具有明显的优势。随着数据量的增加,Solr的搜索效率会变得更低,而Elasticsearch却没有明显的变化。综上所述,
  5. Solr的架构不适合实时搜索的应用。Solr 是传统搜索应用的有力解决方案,但 Elasticsearch 更适用于新兴的实时搜索应用。


Elasticsearch 的安装和使用

注意

Elasticsearch是使用 Java 开发的,所以需要最好使用 jdk1.8 以上的版本。这里设计到的是 es 5.0+ 的版本,6以上版本的还没去了解就不说了,不过5跟6版本区别还是有点大的,5+版本更加稳定。有 jdk1.8+以上版本还不够,请确保是否已经配置的 jdk环境变量,否则 es 服务会启动失败。

安装

直接上官网安装就得了,官网地址: https://www.elastic.co/products/elasticsearch

步骤

  1. 这里使用的是window版本,将下载好的 ES 压缩包解压就完成了,没什么多大问题!

  2. 进入bin目录启动服务,elasticsearch.bat

  3. 有个config目录,这是存放配置文件的,elasticsearch.yml这里面可以改 集群标识名、端口号等

  4. 图形化界面,直接用谷歌浏览器,去谷歌插件商店下载elasticsearch head搞定!

  5. 在浏览器访问http://localhost:9200 得到如下信息,就安装成功了。
    在这里插入图片描述
    注意:如果在配置文件中改了端口,那么访问的地址也要改成对应的端口。



Elasticsearch 概念

Elasticsearch 与数据库对比

个人觉得用比较会更直观更好的理解,拿mysql数据库为例:

mysqlelasticsearch
Database(数据库)Indices(索引库)
Table(数据表)Type(类型)
Rows(表中的一行数据)Documents(文档对象)
Columns(字段名)Fields
Index(字段对应的值)Index(一样,其实也就是数据)

可以看出两个很相似,这样看上去如果不好理解,那么配合图形界面来理解会比较容易!
在这里插入图片描述


Elasticsearch 概念

这里概念就不细说了,官方文档更直观一点。

  1. 集群 cluster:Elasticsearch 的好处就是支持集群,一个集群是由一个或多个节点组织在一起的。共同拥有整个数据,一起提供索引和搜索功能(分片提供的)一个集群会有一个唯一的名称标识,不配置默认集群名为elasticsearch,如需要修改则取 Elasticsearch 的配置文件修改即可。只要节点的集群名称相同,就可以加入同一个集群中。
  2. 节点node:一个节点是集群中的一个服务器,作为集群的一部分。
  3. 索引 Indices:就是索引库,放索引(数据)的。
  4. 类型 type:在一个索引中,你可以定义一种或多种类型。其实也就是分门别类。比如冰箱、电视、洗衣机,都归为电器一类。这里面也是如此,没有强制要求。
  5. 文档 document:数据载体,一个文档是一个可被索引的基础信息单元。(json格式的数据)
  6. 分片和复制:一个索引可以存储超出单个节点硬件限制的大量数据。当索引(数据)过多过大时,可以通过分片将索引分成很多份,效率就能够提高。而复制也就是备份,起一个修复的作用。
  7. 映射 mapping:其实也就是做限制的,拿数据库举例,数据库中数据表的字段是不是有数据类型的限制,比如 varchar、int、date类型等,elasticsearch中也就类型的限制,同样也是对字段进行限制。其不仅可以限制数据类型,而且还可以设置指定的分析器、默认值、是否被索引等等。。




Elasticsearch的Java Api

elasticsearch环境配置

流程:
  1. 创建maven工程,导依赖
  2. 因为遵循了restful风格,所以创建TransportClient通过传输模式来连接到一个elasticsearch的集群,定义成静态工厂方法,方便调用
  3. 通过TransportClient对象创建索引库
步骤:

创建工程,导入依赖

<!-- es核心包 -->
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>5.6.8</version>
</dependency>
<!-- 传输包 -->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>transport</artifactId>
    <version>5.6.8</version>
</dependency>
<!-- 日志包 -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-to-slf4j</artifactId>
    <version>2.9.1</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.24</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>1.7.21</version>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.12</version>
</dependency>
<!-- 测试包,直接运行看效果 -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.10</version>
</dependency>
<!-- jaskon包 -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.9.6</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.6</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.9.6</version>
</dependency>

创建传输客户端,之后直接调用即可

/**
 * 1.创建settings对象,相当于是一个配置信息,配置集群的名称,不配置会默认使用elasticsearch
 * 2.创建一个传输client对象
 * 3.连接一个elasticsearch的集群
 */
public class IndexManager {
    public static TransportClient getTransportClient() throws Exception {
        // 1.创建settings对象,使用默认配置的集群
        Settings settings = Settings.EMPTY;
        //使用指定集群的配置
//        Settings settings = Settings.builder().put("cluster.name","cluster-es").build();

        // 2.创建一个传输client对象
        TransportClient client = new PreBuiltTransportClient(settings);
        
        // 3.连接一个elasticsearch的集群
        client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300));
        
        // 返回一个client对象
        return client;
    }
}

创建索引库,方便测试都在同一个类中,后面直接写方法

//创建索引库
@Test
public void createIndexResp() throws Exception {
    // 1.获取client对象
    TransportClient client = getTransportClient();
    
    // 2.Using an IndicesAdminClient, you can create an index with all default settings and no mapping:		通过索引管理对象,你可以创建一个默认无mapping配置的索引库(名称为blog),通过get发送请求给 es服务,es服务会返回一个响应数据(为json数据)。
    CreateIndexResponse response = client.admin().indices().prepareCreate("blog").get();
    
    //打印 response.isAcknowledged()为true则创建成功
    System.out.println("response = " + response.isAcknowledged());

    //关闭client对象,每次调用后都要关闭资源
    client.close();
}



Elasticsearch 创建文档

创建文档对象

使用 java 的 api完成索引(数据)的创建,也就是对原始数据的写入索引库中。

  1. 使用XContentFactory.jsonBuilder创建
  2. 使用pojo实体类的方式创建

注意:不止这两种方式,最后都是用过json的格式传递

第一种方式:

@Test
public void createIndex() throws Exception {
    // 1.获取client对象
    TransportClient client = getTransportClient();

    // 2.创建索引文档对象,文档数据为json格式,使用工厂类创建
    XContentBuilder xContentBuilder = XContentFactory.jsonBuilder()
        .startObject()      //开启json对象存储,相当于 {
        .field("id", 1)
        .field("title", "elasticsearch是一个基于lucene的搜索服务")
        .field("content", "ElasticSearch是一个基于Lucene的搜索服务器。")
        .endObject();//结束json对象存储,相当于 }

    // 使用client对象将索引文档对象等,封装发送请求到es服务端,如果有索引库则插入数据,如果没有索引库则创建索引库
    // setSource() :为存储其文档信息,
    IndexResponse indexResponse = client
        .prepareIndex("blog2", "content")
        .setSource(xContentBuilder)
        .get();
    
    // 3.关闭资源
    client.close();
}

第二种方式:需要先创建一个实体类(基本操作,这里不演示)

@Test
public void createIndex2() throws Exception {
    // 1.获取client客户端对象
    TransportClient client = getTransportClient();

    // 2.创建实体类Blog对象,设置数据
    Blog blog = new Blog();
    blog.setId(3L);		//long类型
    blog.setTitle("elasticsearch是一个基于lucene的搜索服务");		//string类型
    blog.setContent("elasticsearch是一个基于lucene的搜索服务");	//string类型
    blog.setPrice(30.1f);	//float类型

    // 3.将对象转换json字符串
    ObjectMapper objectMapper = new ObjectMapper();
    String jsonData = objectMapper.writeValueAsString(blog);

    // 4.封装数据,创建索引库
    /*
     * prepareIndex() :参数1:索引库名  参数2:type类型(表名) 参数3:索引库rows行id,不写会自动	 *                   生成16位码
     * setSource():设置要封装发送的数据
     */
    IndexResponse indexResponse = client
            .prepareIndex("blog3", "article", blog.getId() + "")
            .setSource(jsonData, XContentType.JSON)
            .get();
    
    // 5.关闭资源
    client.close();
}



Elasticsearch 修改文档

修改文档也有两种方式
  1. 直接覆盖的方式:仍使用创建文档的步骤,根据表中每一行的索引id进行修改,类似于数据库修改操作,通过条件修改
  2. 通过调用修改的方法进行修改,也是通过条件的判断来修改

第一种方式:

@Test
public void createIndex2() throws Exception {
    // 1.获取client客户端对象
    TransportClient client = getTransportClient();

    // 2.创建实体类Blog对象,设置数据
    Blog blog = new Blog();
    blog.setId(3L);		//long类型
    blog.setTitle("跟上面创建文档的一样,内容修改。相当于覆盖,先删除原数据,再添加新数据");		//string类型
    blog.setContent("跟上面创建文档的一样,内容修改。相当于覆盖,先删除原数据,再添加新数据");	//string类型
    blog.setPrice(30.1f);	//float类型

    // 3.将对象转换json字符串
    ObjectMapper objectMapper = new ObjectMapper();
    String jsonData = objectMapper.writeValueAsString(blog);

    // 4.封装数据,创建索引库
    /*
     * prepareIndex() :参数1:索引库名  参数2:type类型(表名) 参数3:索引库rows行id,不写会自动	 *                   生成16位码
     * setSource():设置要封装发送的数据
     */
    IndexResponse indexResponse = client
            .prepareIndex("blog3", "article", "3")//上面的已经定义过id了,这里我们指定id,直接通过id作为条件,进行修改
            .setSource(jsonData, XContentType.JSON)
            .get();
    
    // 5.关闭资源
    client.close();
}

注意:这种修改的方式,是将已有的_id进行先删除,再添加了新的数据

第二种方式

@Test
public void updateIndex() throws Exception {
    //1.获取client客户端对象
    TransportClient client = getTransportClient();
    
    //2.修改
    Blog blog = new Blog();
    blog.setId(4L);
    blog.setTitle("通过调用修改api进行修改,prepareUpdate(),索引id为3的进行修改");
    blog.setContent("通过调用修改api进行修改,prepareUpdate(),索引id为3的进行修改");
    blog.setPrice(66f);

    //3.将对象转换json字符串
    ObjectMapper objectMapper = new ObjectMapper();
    String jsonData = objectMapper.writeValueAsString(blog);

    //4.调用修改的api,根据指定的索引id修改,传入要修改的数据,发送请求
    UpdateResponse updateResponse = client.prepareUpdate("blog3", "article","3").setDoc(jsonData, XContentType.JSON).get();
    
	//5.关闭资源
    client.close();
}



Elasticsearch 删除文档

利用ElasticSearch中Java的API完成对索引的删除文档操作
  1. 删除索引库中的一条索引数据

    @Test
    public void deleteData() throws Exception {
        //1.获取client客户端对象
        TransportClient client = getTransportClient();
        
        //2.发送删除索引库指定数据的请求
        /*
         * client.prepareDelete("blog3", "article", "4")
         * 参数一:索引库(数据库)		参数二:type类型(表)	参数三:索引id(_id)
         */
        DeleteResponse deleteResponse = client.prepareDelete("blog3", "article", "4").get();
    
        //3.关闭资源
        client.close();
    }
    
  2. 删除一个索引库

    @Test
    public void deleteIndex() throws Exception {
        //1.获取client客户端对象
        TransportClient client = getTransportClient();
    
        //2. 删除对应名称的索引库
        DeleteIndexResponse response = client.admin().indices().prepareDelete("blog3").get();
    
        //3. 关闭资源
        client.close();
    }
    




IKAnalyzer分析器

介绍

​ elasticsearch搜索中文,可能并不会有你如期的效果。不过你可以在github上找一个IKAnalyzer分析器,可以解决中文语义上更好的搜索效果。

​ 下载好后,解压到elasticsearch的plugins目录中。在plugins目录中,有一个config目录,里面是存放配置文件的,也存放着词库。可以新建词库,或者增加停顿词,扩展性高。定义好词库后,打开IKAnalyzer.cfg.xml文件,将使用的词库和停顿词库添加进去,重启es服务即可。

配置
  1. 打开plugins\ik\config目录,找到IKAnalyzer.cfg.xml,配置扩展词库和停顿词词库
    在这里插入图片描述

  2. 修改main.dic,增加自定义的词条

    大碗宽面
    蓝瘦香菇
    程序员
    
  3. 修改stopword.dic,增加停顿词条

    and
    
  4. 重启服务后,可以看到插件和配置文件已被加载
    在这里插入图片描述


测试

IK提供了两个分词算法ik_smartik_max_word 其中 ik_smart 为最小切分,ik_max_word为最细粒度划分 :

分别来试一下

在浏览器地址栏输入下列地址

# 最小切分
http://127.0.0.1:9200/_analyze?analyzer=ik_smart&pretty=true&text=我是唱着大碗宽面and蓝瘦香菇程序员

# 最细切分
http://127.0.0.1:9200/_analyze?analyzer=ik_max_word&pretty=true&text=我是唱着大碗宽面and蓝瘦香菇的程序员

输出的结果为:

  1. 最小划分结果图,and为停顿词被忽略不分词

    在这里插入图片描述

  2. 最细划分结果图,and为停顿词被忽略不分词,按照词库划分后,再按照最细语义划分。
    在这里插入图片描述




Elasticsearch 配置mapping映射

意义:

不配置mapping映射,会默认创建一个无mapping的索引库

Using an IndicesAdminClient, you can create an index with all default settings and no mapping

语法举例:

CreateIndexResponse response = client.admin().indices().prepareCreate("blog").get();
解释:
无论是mapping还是映射从字面上看,都知道是产生的数据文档存储到ES内部文档的一种对应关系。这种对应关系决定了文档存储数据的准确性。只有知道了文档中每个域数据的实际存储含义,才能完成正确的存储和搜索。正如同为一个字符串,映射为全文文本(text)和关键字(keyword)有截然不同的含义。全文文本可以在分词后,被搜索查询,而关键字的功能更偏向于数据精准匹配和聚合分析。

而映射就是针对一种索引下的类型定义,同时映射的域的类型有多种:

域数据类型:

​ 简单数据类型如 text, keyword, date, long, double, boolean or ip.(不再有string类型)

​ 复杂对象类型如 object or nested

​ 特殊的数据类型如 geo_point, geo_shape, or completion.

前提:

配置mapping类型映射,前提得索引库是一个空库,也就是没有任何配置、也没有数据的单纯的一个库;配置mapping只要符合这个条件就可以。(下面是创建一个库并且配置mapping的代码)

startObject:相当于一个左大括号“{”

endObject:相当于一个右大括号“}”

//创建索引库,并且给索引库定义规则。注意:被定义规则的库必须已创建并且不能有数据(也就是不能够有规则)
@Test
public void createMapping() throws Exception {
    //1.获取client客户端对象
    TransportClient client = getTransportClient();

    //2.创建索引库,需要是一个空的库,只有空的库才能够定义规则
    CreateIndexResponse response = client.admin().indices().prepareCreate("blog").get();
    System.out.println("response.isShardsAcked() = " + response.isShardsAcked());

    //3.判断是否创建成功
    if (response.isShardsAcked()) {
        //4.给创建的索引库指定规则,规则需要是json格式的数据,这里使用了分析器,并且时最小划分
        XContentBuilder builder = XContentFactory.jsonBuilder()
                .startObject()	
                .startObject("article")
                .startObject("properties")
                .startObject("id").field("type", "long").field("store", true).endObject()
                .startObject("title").field("type", "text").field("store", true).field("analyzer", "ik_smart").endObject()
                .startObject("content").field("type", "text").field("store", true).field("analyzer", "ik_smart").endObject()
                .startObject("price").field("type", "float").field("store", true).endObject()
                .endObject()
                .endObject()
                .endObject();

        //5.发送创建索引库的请求
        PutMappingResponse putMappingResponse = client.admin().indices().preparePutMapping("blog")
                .setType("article")
                .setSource(builder)
                .get();
        System.out.println("putMappingResponse = " + putMappingResponse.isAcknowledged());
    }

    //6.关闭资源
    client.close();
}

定义后的mapping对应关系图:
在这里插入图片描述




Elasticsearch 实现搜索

实现搜索的功能

注意:搜索前确保自己的库中有对应的数据

elasticsearch提供了很多种搜索的api,下面只列举几种常用的:

  1. QueryBuilders.matchAllQuery():查询全部
  2. QueryBuilders.queryStringQuery(keyword):通过关键字查询
  3. QueryBuilders.termQuery("columns","property"):根据词条查询,第一个参数也就是字段名,第二个参数其实就是要查询的 “词条”
  4. QueryBuilders.idsQuery("type").addIds("_id","_id",...,"_id"):根据_id查询,根据指定的type(表)查询符合索引id的数据,索引id在es服务图形界面上是 _id的形式
  5. QueryBuilders.wildcardQuery("columns","value*"):模糊查询:使用通配符查询,单字符通配符?,多字符通配符*,根据查询的词在对应的columns(字段)做查询。

QueryBuilders.matchAllQuery():查询全部
@Test
public void queryAll() throws Exception {
    //1.获取client客户端对象
    TransportClient client = getTransportClient();
    
    //2.定义查询条件对象
    //查询全部
    QueryBuilder builder = QueryBuilders.matchAllQuery();

    //3.使用client进行查询,可以查询多个索引库,跨库跨表都可以
    //client.prepareSearch("blog2"):参数可以配置多个,也就是跨库
    SearchResponse searchResponse = client.prepareSearch("blog2")
        .setTypes("content")    //什么都不定义的话是跨库跨表搜索,定义类型的话,是指定表的类型搜索
        //.setPostFilter(QueryBuilders.rangeQuery("price").from(20f).to(30f))   setPostFilter:定义一个过滤器,将符合过滤器条件的也加入筛选条件中
        //.addSort("price", SortOrder.ASC)     //addSort():排序,根据指定的字段来排序
        .setQuery(builder)	//将上面定义好的查询条件对象放入
        .get();
    
    //4.得到查询的结果,获取命中数
    SearchHits hits = searchResponse.getHits();
    System.out.println("一共命中个数为:"+hits.totalHits);
    
    //5.遍历命中数,将查询到的数据展示出来
    for (SearchHit hit : hits) {
        Map<String, Object> sourceAsMap = hit.getSourceAsMap();
        System.out.println(sourceAsMap.get("id"));
        System.out.println(sourceAsMap.get("title"));
        System.out.println(sourceAsMap.get("content"));
        //            System.out.println(sourceAsMap.get("price"));
        System.out.println("==============================================");
    }
    
    //6.关闭资源
    client.close();
}

search中还有很多链式调用的方法,大家有兴趣可以研究



QueryBuilders.queryStringQuery(keyword):通过关键字查询
@Test
public void queryAll() throws Exception {
    //1.获取client客户端对象
    TransportClient client = getTransportClient();
    
    //2.定义查询条件对象
    //根据多关键字搜索	:多关键词搜索使用的 一元切法
    QueryBuilder builder = QueryBuilders
        .queryStringQuery("我要买一本elasticsearch书籍")
        .defaultField("title");		//title:在指定的字段查询,自定义

    //3.使用client进行查询,可以查询多个索引库
    SearchResponse searchResponse = client.prepareSearch("blog2")
        .setTypes("content")    //什么都不定义的话是跨库跨表搜索,定义类型的话,是指定表的类型搜索
        //.setPostFilter(QueryBuilders.rangeQuery("price").from(20f).to(30f))   		  setPostFilter:定义一个过滤器,将符合过滤器条件的也加入筛选条件中
        //.addSort("price", SortOrder.ASC)     //addSort():排序,根据指定的字段来排序
        .setQuery(builder)
        .get();

    //4.得到查询的结果,获取命中数
    SearchHits hits = searchResponse.getHits();
    System.out.println("一共命中个数为:"+hits.totalHits);

    //5.遍历命中数,将查询到的数据展示出来
    for (SearchHit hit : hits) {
        Map<String, Object> sourceAsMap = hit.getSourceAsMap();
        System.out.println(sourceAsMap.get("id"));
        System.out.println(sourceAsMap.get("title"));
        System.out.println(sourceAsMap.get("content"));
        //            System.out.println(sourceAsMap.get("price"));
        System.out.println("==============================================");
    }

    //6.关闭资源
    client.close();
}



QueryBuilders.termQuery("columns","property"):根据词条查询
@Test
public void queryAll() throws Exception {
    //1.获取client客户端对象
    TransportClient client = getTransportClient();
    
    //2.定义查询语句,根据什么字段查询
    //根据词条查询,在字段title中查询含有 词条“elasticsearch”的数据
    QueryBuilder builder = QueryBuilders.termQuery("title","elasticsearch");
    
    //3.使用client进行查询,可以查询多个索引库
    SearchResponse searchResponse = client.prepareSearch("blog2")
        .setTypes("content")    //什么都不定义的话是跨库跨表搜索,定义类型的话,是指定表的类型搜索
        //.setPostFilter(QueryBuilders.rangeQuery("price").from(20f).to(30f))   setPostFilter:定义一个过滤器,将符合过滤器条件的也加入筛选条件中
        //.addSort("price", SortOrder.ASC)     //addSort():排序,根据指定的字段来排序
        .setQuery(builder)
        .get();
    
    //4.得到查询的结果,获取命中数
    SearchHits hits = searchResponse.getHits();
    System.out.println("一共命中个数为:"+hits.totalHits);
    
    //5.遍历命中数,将查询到的数据展示出来
    for (SearchHit hit : hits) {
        Map<String, Object> sourceAsMap = hit.getSourceAsMap();
        System.out.println(sourceAsMap.get("id"));
        System.out.println(sourceAsMap.get("title"));
        System.out.println(sourceAsMap.get("content"));
        //            System.out.println(sourceAsMap.get("price"));
        System.out.println("==============================================");
    }
    
    //6.关闭资源
    client.close();
}



QueryBuilders.idsQuery("type").addIds("_id","_id",...,"_id"):根据_id查询
@Test
public void queryAll() throws Exception {
    //1.获取client客户端对象
    TransportClient client = getTransportClient();
    
    //2.定义查询语句,根据什么字段查询
    //根据_id搜索,也就是根据索引 id 查询,可以传入多个id。在content表中查询id为如下的数据。
    QueryBuilder builder = QueryBuilders.idsQuery("content").addIds("1","4","20");
    
    //3.使用client进行查询,可以查询多个索引库
    SearchResponse searchResponse = client.prepareSearch("blog2")
        .setTypes("content")    //什么都不定义的话是跨库跨表搜索,定义类型的话,是指定表的类型搜索
        //.setPostFilter(QueryBuilders.rangeQuery("price").from(20f).to(30f))   setPostFilter:定义一个过滤器,将符合过滤器条件的也加入筛选条件中
        //.addSort("price", SortOrder.ASC)     //addSort():排序,根据指定的字段来排序
        .setQuery(builder)
        .get();
    
    //4.得到查询的结果,获取命中数
    SearchHits hits = searchResponse.getHits();
    System.out.println("一共命中个数为:"+hits.totalHits);
    
    //5.遍历命中数,将查询到的数据展示出来
    for (SearchHit hit : hits) {
        Map<String, Object> sourceAsMap = hit.getSourceAsMap();
        System.out.println(sourceAsMap.get("id"));
        System.out.println(sourceAsMap.get("title"));
        System.out.println(sourceAsMap.get("content"));
        //            System.out.println(sourceAsMap.get("price"));
        System.out.println("==============================================");
    }
    
    //6.关闭资源
    client.close();
}



QueryBuilders.wildcardQuery("columns","value*"):模糊查询

*:表示可以匹配多个字符

?:表示匹配一个字符,几个?表示匹配几个字符

@Test
public void queryAll() throws Exception {
    //1.获取client客户端对象
    TransportClient client = getTransportClient();
    
    //2.定义查询语句,根据什么字段查询
    //模糊搜索  query:对应的是通配符,"?"通配符只表示一个字符,"*"通配符表示多个字符
    //QueryBuilder builder = QueryBuilders.wildcardQuery("title","elastic?");//查不到
    QueryBuilder builder = QueryBuilders.wildcardQuery("title","elastic*");
    
    //3.使用client进行查询,可以查询多个索引库
    SearchResponse searchResponse = client.prepareSearch("blog2")
        .setTypes("article")    //什么都不定义的话是跨库跨表搜索,定义类型的话,是指定表的类型搜索
        //.setPostFilter(QueryBuilders.rangeQuery("price").from(20f).to(30f))   setPostFilter:定义一个过滤器,将符合过滤器条件的也加入筛选条件中
        //.addSort("price", SortOrder.ASC)     //addSort():排序,根据指定的字段来排序
        .setQuery(builder)
        .get();
    
    //4.得到查询的结果,获取命中数
    SearchHits hits = searchResponse.getHits();
    System.out.println("一共命中个数为:"+hits.totalHits);
    
    //5.遍历命中数,将查询到的数据展示出来
    for (SearchHit hit : hits) {
        Map<String, Object> sourceAsMap = hit.getSourceAsMap();
        System.out.println(sourceAsMap.get("id"));
        System.out.println(sourceAsMap.get("title"));
        System.out.println(sourceAsMap.get("content"));
        //            System.out.println(sourceAsMap.get("price"));
        System.out.println("==============================================");
    }
    
    //6.关闭资源
    client.close();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值