草庐IT

ElasticSearch系列——Elasticsearch Java API Client

简明编程 2023-05-11 原文

ElasticSearch系列——Elasticsearch Java API Client

Elasticsearch Java API Client

这是用于Elasticsearch的官方Java API客户端的文档。客户端为所有Elasticsearch API提供强类型请求和响应。我们要注意原来的HighRestAPIClient以及停用了,这是趋势,包括SpringData-ElasticSearch4.4.5之后配合ES8的推出也会更换

官方地址

https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/7.17/indexing.html

特点

  1. 所有Elasticsearch API的强类型请求和响应。
  2. 所有API的阻塞和异步版本。
  3. 使用流畅的构建器和函数模式,在创建复杂的嵌套结构时,允许编写简洁但可读的代码
  4. 通过使用对象映射器(如杰克逊或任何JSON-B实现)无缝集成应用程序类。
  5. 将协议处理委托给http客户端(如Java低级REST客户端),该客户端负责处理所有传输级问题:HTTP连接池、重试、节点发现等。

需求

  1. Java11版本
  2. 一 个 JSON 对象映射库,允许您的应用程序类与Elasticsearch API无缝集成 ,Java 客户端支持 Jackson 或 JSON-B 库 ( 如 Eclipse Yasson )

核心三大组成

Java API客户端由三个主要组件构成:

  1. API client classes(API客户端类)。它们为Elasticsearch API提供了强类型数据结构和方法。由于Elasticsearch API很大,它以特性组(也称为“命名空间”)的形式进行结构化,每个特性组都有自己的客户端类。Elasticsearch核心功能在ElasticsearchClient类中实现。
  2. A JSON object mapper(JSON对象映射器):这将应用程序类映射到JSON,并将它们与API客户机无缝集成。
  3. A transport layer implementation(一种传输层实现):这是所有HTTP请求处理发生的地方。

包和命名空间

Elasticsearch API很大,并被组织成功能组,这可以在Elasticsearch API文档中看到。

Java API客户端遵循以下结构:特征组被称为“命名空间”,并且每个命名空间位于co.elastic.clients.elasticsearch的子包中。

每个命名空间客户端都可以从顶级Elasticsearch客户端访问。唯一的例外是“search”和“document”API,它们位于核心子包中,可以在主Elasticsearch客户端对象上访问。

QuickStart

1.导入依赖

这里记住你的elasticsearch-java必须对应你电脑上装的ES版本

	<dependency>
      <groupId>co.elastic.clients</groupId>
      <artifactId>elasticsearch-java</artifactId>
      <version>7.17.6</version>
    </dependency>

    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.12.3</version>
    </dependency>
    <dependency>
      <groupId>jakarta.json</groupId>
      <artifactId>jakarta.json-api</artifactId>
      <version>2.0.1</version>
    </dependency>

2.开启连接

        //创建一个低级的客户端
        final RestClient restClient = RestClient.builder(new HttpHost("localhost", 9200)).build();
        //创建JSON对象映射器
        final RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        //创建API客户端
        final ElasticsearchClient client = new ElasticsearchClient(transport);

3.关闭连接

        client.shutdown();
        transport.close();
        restClient.close();

完整代码

public class Client {
    public static void main(String[] args) throws IOException {
        //创建一个低级的客户端
        final RestClient restClient = RestClient.builder(new HttpHost("localhost", 9200)).build();
        //创建JSON对象映射器
        final RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        //创建API客户端
        final ElasticsearchClient client = new ElasticsearchClient(transport);
        //查询所有索引-------------------------------------------------------------------------------------
        final GetIndexResponse response = client.indices().get(query -> query.index("_all"));
        final IndexState products = response.result().get("products");
        System.out.println(products.toString());
        //关闭
        client.shutdown();
        transport.close();
        restClient.close();
    }
}

@JsonIgnore注解

标记注释,指示访问器(字段、getter/setter方法或[JsonCreator带注释的构造函数或工厂方法]的Creator参数)的逻辑属性将被基于内省的序列化和反序列化功能忽略。

上面是官方的解释,在我们的ES API中这个注解用于在实体类上的某个属性进行添加,用于忽略这个属性,即使用该注解标注的属性在查询时会被输出为null(前提是你设置了映射含有,若本来就没有映射,则不会看到这个属性),而在创建时则会直接忽略
例如:

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Produce {
    @JsonIgnore
    private String sku;
    private String name;
    private String des;
    private double price;
}

我们在sku上添加了这个注解,那么创建文档时就不会有这个属性(请大家运行以下代码进行验证即可),一般我们在真实业务中也会这样做,因为文档的_id字段会与之重合导致不必要的数据冗余

public class CreateDocClass {
    public static void main(String[] args) throws IOException {
        final RestClient restClient = RestClient.builder(new HttpHost("localhost", 9200)).build();
        final RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        final ElasticsearchClient client = new ElasticsearchClient(transport);
        //创建文档
        final Produce produce = new Produce("aabbcc555", "旺仔牛比糖", "旺仔牛比糖吃了炒鸡牛笔", 6.66D);
        final IndexResponse response = client.index(builder -> builder.index("produces").id(produce.getSku()).document(produce));
        System.err.println(response.version());
        client.shutdown();
        transport.close();
        restClient.close();
    }
}

JsonData类

原始JSON值。可以使用JsonpMapper将其转换为JSON节点树或任意对象。 此类型在API类型中用于没有静态定义类型或无法表示为封闭数据结构的泛型参数的值。 API客户端返回的此类实例保留对客户端的JsonpMapper的引用,并且可以使用to(class)转换为任意类型,而不需要显式映射器

我们一般在ES的DSL范围查询中会使用到!
核心方法:

  1. to:将此对象转换为目标类。必须在创建时提供映射器
  2. from:从读取器创建原始JSON值
  3. of:从现有对象创建原始JSON值,以及用于进一步转换的映射器
  4. deserialize:使用反序列化程序转换此对象。必须在创建时提供映射器

这个类不多大家自己看一下应该就知道怎么用了,位于package co.elastic.clients.json;

API使用

以下所有API和我之前的文章对应请查看:ElasticSearch系列——Kibana,核心概念的使用Kibana对ES进行操作部分

开启连接

  1. 构建RestClient低级客户端
  2. 构建对象映射器
  3. 构建ES的API客户端
        final RestClient restClient = RestClient.builder(new HttpHost("localhost", 9200)).build();
        final RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        final ElasticsearchClient client = new ElasticsearchClient(transport);

关闭连接

对应开启

  1. 关闭ES的API客户端
  2. 关闭对象映射器
  3. 关闭低级客户端
        client.shutdown();
        transport.close();
        restClient.close();

查询所有索引

indices是index的复数
其实看起来很好理解
使用GET方法进行查询index
查询所有的就是GET http://localhost:9200/_all

//省略连接...
        final GetIndexResponse all = client.indices().get(query -> query.index("_all"));
        System.out.println(all.toString());
//省略关闭...

查询某个索引

原来我们使用GET http://localhost:9200/索引名称这里也是一样设置索引名称即可

        //查询某个索引
        final GetIndexResponse products = client.indices().get(query -> query.index("products"));
        System.err.println(products.toString());

创建索引

//创建指定索引
        boolean exists = client.indices().exists(query -> query.index("products")).value();
        System.out.println(exists);
        if (exists) {
            System.err.println("索引已存在");

        } else {
            final CreateIndexResponse products = client.indices().create(builder -> builder.index("products"));
            System.err.println(products.acknowledged());
        }

删除指定索引

        //删除指定索引
        boolean exists = client.indices().exists(query -> query.index("products")).value();
        System.out.println(exists);
        if (exists) {
            DeleteIndexResponse response = client.indices().delete(query -> query.index("products"));
            System.err.println(response.acknowledged());
        } else {
            System.err.println("索引不存在");
        }

查询索引的映射

没有直接去查映射的是根据索引向下找到映射信息,主要是一下代码

response.result().get(索引名称).mappings(
        //查询映射信息
        final GetIndexResponse response = client.indices().get(builder -> builder.index("produces"));
        System.err.println(response.result().get("produces").mappings());

创建索引指定映射

  1. numberOfReplicas(“1”):设置副本
  2. numberOfShards(“1”):设置分片
        //创建索引指定映射,分片和副本信息
        final CreateIndexResponse response = client.indices().create(builder ->
                builder.settings(indexSetting -> indexSetting.numberOfReplicas("1").numberOfShards("1")).mappings(
                        map -> map
                                .properties("name", propertyBuilder -> propertyBuilder.keyword(keywordProperty -> keywordProperty))
                                .properties("price", propertyBuilder -> propertyBuilder.double_(doubleNumProperty -> doubleNumProperty))
                                .properties("des", propertyBuilder -> propertyBuilder.text(textProperty -> textProperty.analyzer("ik_smart").searchAnalyzer("ik_smart")))
                ).index("produces")

        );

创建文档

使用HashMap作为数据存储容器

        //创建文档
        //1.创建HashMap进行存储数据,文档要对应映射
        final HashMap<String, Object> doc = new HashMap<>();
        doc.put("name","辣条");
        doc.put("price",5.62D);
        doc.put("des","卫龙辣条,草鸡好吃");
        //2.将文档存入索引中
        final IndexResponse response = client.index(builder -> builder.index("produces").id("116688").document(doc));
        System.err.println(response.version());

在我们使用HashMap的时候我们可以将文档的ID直接放在Map里,如下:
但是我们要知道的是如果你这样设置了,你的索引的映射就会变化增加一个id的映射

        //创建文档
        //1.创建HashMap进行存储数据,文档要对应映射
        final HashMap<String, Object> doc = new HashMap<>();
        doc.put("id","116677");
        doc.put("name","辣条");
        doc.put("price",5.62D);
        doc.put("des","卫龙辣条,草鸡好吃");
        //2.将文档存入索引中
        final IndexResponse response = client.index(builder -> builder.index("produces").id(doc.get("id").toString()).document(doc));
        System.err.println(response.version());

使用自定义类作为数据存储容器

实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Produce {
    private String sku;
    private String name;
    private String des;
    private double price;
}
        //创建文档
        final Produce produce = new Produce("aabbcc123", "旺仔牛比糖", "旺仔牛比糖吃了炒鸡牛笔", 6.66D);
        final IndexResponse response = client.index(builder -> builder.index("produces").id(produce.getSku()).document(produce));
        System.err.println(response.version());

使用外部JSON数据创建

这里要注意我们需要使用StringReader进行读取时使用replace函数将设置的'改为",当然这在真实的业务中肯定不会有,因为真实业务中一定是标准的JSON数据,无需使用replace进行替换了

        //创建文档
        final StringReader input = new StringReader(
                "{'name':'农夫三拳','price':3.00,'des':'农夫三拳有点甜'}".replace('\'', '"')
        );
        final IndexResponse response = client.index(builder -> builder.index("produces").id("44514").withJson(input));
        System.err.println(response.version());

查询所有文档

        //查询所有文档
        final SearchResponse<Object> response = client.search(builder -> builder.index("produces"), Object.class);
        final List<Hit<Object>> hits = response.hits().hits();
        hits.forEach(
                x-> System.err.println(x)
        );

根据ID查询文档

使用HashMap对应查询

        //查询文档
        final GetResponse<Map> response = client.get(builder -> builder.index("produces").id("116677"), Map.class);
        final Map source = response.source();
        source.forEach((x,y)->{
            System.err.println(x+":"+y);
        });

使用自定义类对应查询

        final GetResponse<Produce> response1 = client.get(builder -> builder.index("produces").id("aabbcc123"), Produce.class);
        final Produce source1 = response1.source();
        System.err.println(source1.toString());

删除指定文档

        //根据ID删除文档
        final DeleteResponse response = client.delete(builder -> builder.index("produces").id("44514"));
        System.err.println(response.shards().successful());

修改文档

覆盖写

        //修改文档(覆盖)
        final Produce produce = new Produce("ccaabb123", "旺仔摇滚洞", "旺仔摇滚洞乱摇乱滚", 10.23D);
        final UpdateResponse<Produce> response = client.update(builder -> builder.index("produces").id("aabbcc123").doc(produce), Produce.class);
        System.err.println(response.shards().successful());

修改部分文档

区别在于我们需要设置.docAsUpsert(true)表明是修改部分而不是覆盖

        //修改文档(部分修改)
//        final Produce produce = new Produce("ccaabb123", "旺仔摇滚洞", "旺仔摇滚洞乱摇乱滚", 10.23D);
        final Produce produce = new Produce();
        produce.setName("旺仔摇不动");
        final UpdateResponse<Produce> response = client.update(builder -> builder.index("produces").id("aabbcc123").doc(produce).docAsUpsert(true), Produce.class);
        System.err.println(response.shards().successful());

批量操作

对应批量操作大家应该知道概念:看起来是批量,实际是逐条处理
所以我一开始想要写成for循环的单个文档创建,后来想了一下,如果这样写,其实没有什么必要了,尝试了一下确实有bulk函数,写成lambda方式后发现直接使用lambda构建实际是不行的,会报方法只能调用一次的错误,那么我们就需要在外部先构建出批量的条件然后再直接调用build方法即可final BulkResponse response = client.bulk(br.build());

public class BulkDoc {
    public static void main(String[] args) throws IOException {
        final RestClient restClient = RestClient.builder(new HttpHost("localhost", 9200)).build();
        final RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        final ElasticsearchClient client = new ElasticsearchClient(transport);
        //批量操作
        //准备数据
        final Produce produce1 = new Produce("1000", "风油精", "风油精辣眼睛", 20.23D);
        final Produce produce2 = new Produce("1001", "六神花露水", "蚊虫叮咬就用Six God", 8.28D);
        final Produce produce3 = new Produce("1002", "龙虎万精油", "龙虎牌万精油赶走疲劳做回自己", 13.3D);
        final ArrayList<Produce> produceList = new ArrayList<>();
        produceList.add(produce1);
        produceList.add(produce2);
        produceList.add(produce3);
        //构建BulkRequest
        final BulkRequest.Builder br = new BulkRequest.Builder();
        for (Produce produce : produceList) {
            br.operations(op->op.index(idx->idx.index("produces").id(produce.getSku()).document(produce)));
        }
        final BulkResponse response = client.bulk(br.build());
        System.err.println(response.toString());
        client.shutdown();
        transport.close();
        restClient.close();
    }
}

DSL条件查询

根据具体的条件对文档进行查询,这里的条件就是name为龙虎万精油
注意的是若使用条件查询必须传入一个你要转化得到的实体对象在这里是Produce.class
若你的索引中存了和其不符合的文档则会报错!

        //简单query方式查询
        final SearchResponse<Produce> response = client.search(builder ->
                builder.index("produces")
                        .query(q ->
                                q.match(t ->
                                        t.field("name")
                                                .query("龙虎万精油"))), Produce.class);
        System.err.println(response.hits().hits());

DSL matchAll查询所有文档

        //matchAll
        final SearchResponse<Produce> response = client.search(builder ->
                builder.index("produces")
                        .query(q ->
                                q.matchAll(
                                        v->v
                                )), Produce.class);

        System.err.println(response.hits().hits());

多ID查询(ids)

在values中我们可以传入一个List也可以像我这样直接写多个ID,因为其使用了不定长参数

        //多ID查询
        final SearchResponse<Produce> response = client.search(builder ->
                builder.index("produces")
                        .query(q ->
                                q.ids(sid->sid.values("1000","1001"))), Produce.class);
        System.err.println(response.hits().hits());

term不分词查询

        //term不分词条件查询
        final SearchResponse<Produce> response = client.search(builder -> builder.index("produces")
        .query(q -> q.term(t -> t.field("name").value("风油精"))), Produce.class);
        System.err.println(response.hits().hits());

范围查询

        //范围查询
        final SearchResponse<Produce> response = client.search(builder ->
                        builder.index("produces").query(q ->
                                q.range(r ->
                                        r.field("price").gt(JsonData.of(5D)).lt(JsonData.of(15D)))),
                Produce.class);
        System.err.println(response.hits().hits());

前缀查询

        //前缀查询
        final SearchResponse<Produce> response = client.search(builder ->
                        builder.index("produces").query(q ->q.prefix(p->p.field("name").value("六"))),
                Produce.class);
        System.err.println(response.hits().hits());

匹配查询

*全字符匹配

        //匹配查询
                final SearchResponse<Produce> response = client.search(builder ->
                        builder.index("produces").query(q ->q.wildcard(w->w.field("name").value("风*"))),
                Produce.class);
        System.err.println(response.hits().hits());

?单字符匹配

        //匹配查询
                final SearchResponse<Produce> response = client.search(builder ->
                        builder.index("produces").query(q ->q.wildcard(w->w.field("name").value("风?精"))),
                Produce.class);
        System.err.println(response.hits().hits());

模糊查询

        //模糊查询
        final SearchResponse<Produce> response = client.search(builder ->
                        builder.index("produces").query(q ->q.fuzzy(f->f.field("name").value("六仙花露水"))),
                Produce.class);
        System.err.println(response.hits().hits());

多条件查询

使用bool关键字配合must,should,must_not

  1. must:所有条件必须同时成立
  2. must_not:所有条件必须同时不成立
  3. should:所有条件中成立一个即可
        //多条件
        final SearchResponse<Produce> response = client.search(builder ->
                        builder.index("produces").query(q ->
                                q.bool(b ->
                                        b.must(t ->
                                                t.term(v ->
                                                        v.field("name")
                                                                .value("旺仔摇不动")))
                                         .must(t2 ->
                                                 t2.term(v2 ->
                                                        v2.field("price")
                                                                 .value(0.0D))))),
                Produce.class);
        System.err.println(response.hits().hits());

多字段查询

        //多字段查询
        final SearchResponse<Produce> response = client.search(builder ->
                        builder.index("produces").query(q->q.multiMatch(qs->qs.query("蚊虫叮咬 辣眼睛").fields("name","des"))),
                Produce.class);
        System.err.println(response.hits().hits());

字段分词查询

        //字段分词查询
        final SearchResponse<Produce> response = client.search(builder ->
                        builder.index("produces").query(q->q.queryString(qs->qs.defaultField("des").query("摇滚"))),
                Produce.class);
        System.err.println(response.hits().hits());

高亮显示

我们注意要设置前缀和后缀

        //高亮显示
        final SearchResponse<Produce> response = client.search(builder ->
                        builder.index("produces")
                                .query(q -> q.match(v -> v.field("name").query("风油精")))
                                .highlight(h -> h.preTags("<span>").postTags("<span>").fields("name", hf -> hf)),
                Produce.class);
        System.err.println(response.toString());

分页查询

我们使用match_all进行全部搜索的时候使用size关键字设置每一页的大小,使用from关键字设置页码
from的计算公式:(页码-1)*size

        //分页查询
                final SearchResponse<Produce> response = client.search(builder ->
                        builder.index("produces")
                                .query(q->q.matchAll(v->v)).size(2).from(0),
                Produce.class);
        System.err.println(response.hits().hits());

排序

使用sort关键字指定需要进行排序的字段设置排序类型即可,我们这里会使用到SortOrder枚举类来进行指定排序方式

  1. desc:降序
  2. asc:升序
        //排序
        final SearchResponse<Produce> response = client.search(builder ->
                        builder.index("produces")
                                .query(q->q.matchAll(v->v))
                                .sort(builder1 -> builder1.field(f->f.field("price").order(SortOrder.Asc))),
                Produce.class);
        System.err.println(response.hits().hits());

指定字段查询

使用_source关键字在数组中设置需要展示的字段
值得注意的是在source方法中需要我们写filter去指定是include包含或是exclude去除xx字段

        //指定字段查询
        final SearchResponse<Produce> response = client.search(builder ->
                        builder.index("produces")
                                .query(q->q.matchAll(v->v))
                                .source(s->s.filter(v->v.includes("price","des"))),
                Produce.class);
        System.err.println(response.hits().hits());

有关ElasticSearch系列——Elasticsearch Java API Client的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby-on-rails - 使用一系列等级计算字母等级 - 2

    这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,

  3. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  4. 阿里云RDS——产品系列概述 - 2

    基础版云数据库RDS的产品系列包括基础版、高可用版、集群版、三节点企业版,本文介绍基础版实例的相关信息。RDS基础版实例也称为单机版实例,只有单个数据库节点,计算与存储分离,性价比超高。说明RDS基础版实例只有一个数据库节点,没有备节点作为热备份,因此当该节点意外宕机或者执行重启实例、变更配置、版本升级等任务时,会出现较长时间的不可用。如果业务对数据库的可用性要求较高,不建议使用基础版实例,可选择其他系列(如高可用版),部分基础版实例也支持升级为高可用版。基础版与高可用版的对比拓扑图如下所示。优势 性能由于不提供备节点,主节点不会因为实时的数据库复制而产生额外的性能开销,因此基础版的性能相对于

  5. ruby - Rails Elasticsearch 聚合 - 2

    不知何故,我似乎无法获得包含我的聚合的响应...使用curl它按预期工作:HBZUMB01$curl-XPOST"http://localhost:9200/contents/_search"-d'{"size":0,"aggs":{"sport_count":{"value_count":{"field":"dwid"}}}}'我收到回复:{"took":4,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":90,"max_score":0.0,"hits":[]},"a

  6. ruby - 从结束值创建一系列字符串 - 2

    我使用irb。下面是我写的代码。“斧头”..“bc”我期待"ax""ay""az""ba"bb""bc"但结果只是“斧头”..“bc”我该如何纠正?谢谢。 最佳答案 >puts("ax".."bc").to_aaxayazbabbbc 关于ruby-从结束值创建一系列字符串,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7617092/

  7. elasticsearch源码关于TransportSearchAction【阶段三】 - 2

    1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>

  8. ruby-on-rails - 用一系列时间增量填充选择,加上其他选项 - 2

    使用RubyonRails,我使用给定的增量(例如每30分钟)用时间填充“选择”。目前我正在YAML文件中写出所有的可能性,但我觉得有一种更巧妙的方法。我想我想提供一个开始时间、一个结束时间、一个增量,并且目前只提供一个名为“关闭”的选项(想想“business_hours”)。所以,我的选择可能会显示:'Closed'5:00am5:30am6:00am...[allthewayto]...11:30pm谁能想出更好的方法,或者只是将它们全部“拼写”出来的最佳方法? 最佳答案 此答案基于@emh的答案。defcreate_hour

  9. ruby-on-rails - 使用 Rails (Tire) 和 ElasticSearch 进行模糊字符串匹配 - 2

    我有一个Rails应用程序,现在设置了ElasticSearch和Tiregem以在模型上进行搜索,我想知道我应该如何设置我的应用程序以对模型中的某些索引进行模糊字符串匹配。我将我的模型设置为索引标题、描述等内容,但我想对其中一些进行模糊字符串匹配,但我不确定在何处进行此操作。如果您想发表评论,我将在下面包含我的代码!谢谢!在Controller中:defsearch@resource=Resource.search(params[:q],:page=>(params[:page]||1),:per_page=>15,load:true)end在模型中:classResource'Us

  10. 美团外卖搜索基于Elasticsearch的优化实践 - 2

    美团外卖搜索工程团队在Elasticsearch的优化实践中,基于Location-BasedService(LBS)业务场景对Elasticsearch的查询性能进行优化。该优化基于Run-LengthEncoding(RLE)设计了一款高效的倒排索引结构,使检索耗时(TP99)降低了84%。本文从问题分析、技术选型、优化方案等方面进行阐述,并给出最终灰度验证的结论。1.前言最近十年,Elasticsearch已经成为了最受欢迎的开源检索引擎,其作为离线数仓、近线检索、B端检索的经典基建,已沉淀了大量的实践案例及优化总结。然而在高并发、高可用、大数据量的C端场景,目前可参考的资料并不多。因此

随机推荐