Redis新功能 RedisSearch安装和使用 媲美ES的存在

这篇具有很好参考价值的文章主要介绍了Redis新功能 RedisSearch安装和使用 媲美ES的存在。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

RedisSearch 简介

内容翻译自Redis官网
RedisSearch是一个强大的文本搜索和二级索引引擎,建立在Redis之上作为Redis模块。Redis搜索用C语言编写,与其他开源搜索引擎相比速度极快。它实现了多种数据类型和命令,从根本上改变了您可以使用Redis做什么。Redis搜索支持搜索和过滤功能,例如地理空间查询、仅检索ID(而不是整个文档)和自定义文档评分。聚合可以在自定义管道中组合map、filter和duce/grou-by操作,这些操作在瞬间运行数百万个元素。

RedisSearch安装

第一步:直接放编译后的二进制文件

编译文件是个技术活,会折腾很长时间,有时间的小伙伴可以去尝试一下。
链接:https://pan.baidu.com/s/1stMiYBCMIMcOUd-Qjbpasw
提取码:uhwt

第二步:挂载二进制文件

把redisearch.so拷贝到redis安装目录下的src目录,然后编辑redis.conf
挂载文件
loadmodule /data/redis-6.0.10/src/redisearch.so

最后: 重启redis即可文章来源地址https://www.toymoban.com/news/detail-842931.html

第三 操作方法 不同客户端

jedis

@Autowired
    private UnifiedJedis jedis;

    private String prefix = "$.";

    @PostConstruct
    private void init(){
        createIndex("place-index","place:", new String[]{"provinceName","cityList[*].cityName","cityList[*].geoinfo","cityList[*].countyList[*].countyName"});

    }

    public boolean createIndex(String indexName, String key, String... fields){

        try {

            try{
                Map<String, Object> map = jedis.ftInfo(indexName);
                log.info("index configuration:{}",map);
                jedis.ftDropIndex(indexName);
            } catch (Exception e){
                log.error("the index does not exist", e);
            }

            Schema schema = new Schema();

            float weight = 1.0f;
            for(String field : fields) {
                String attribute;
                if (StringUtils.isNoneBlank(field)) {

                    if (field.indexOf(".") == -1) {
                        attribute = field;
                    } else {
                        String[] fieldSplit = field.split("\\.");
                        attribute = fieldSplit[fieldSplit.length - 1];
                    }

                    if (attribute.toLowerCase().startsWith("geo")) {
                        Schema.Field field1 = new Schema.Field(FieldName.of(prefix + field).as(attribute), Schema.FieldType.GEO);
                        //schema.addGeoField(prefix + field);
                        schema.addField(field1);
                        continue;
                    } else {

                        Schema.TextField textField = new Schema.TextField(FieldName.of(prefix + field).as(attribute), weight, false, false, false, null);
                        schema.addField(textField);
                        weight *= 3;
                        continue;
                    }
                }
            }


            IndexDefinition rule = new IndexDefinition(IndexDefinition.Type.JSON).setLanguage("chinese")
                    .setPrefixes(new String[]{key});


            jedis.ftCreate(indexName,
                    IndexOptions.defaultOptions().setDefinition(rule),
                    schema);
            return true;
        } catch (Exception e){
            log.error("create redis search index failed", e);
            return false;
        }


    }

jedisSearch

@Autowired
    private Client client;

    /**
     * 删除索引
     */
    public void dropIndex(){
        // 只会删除索引,不会删除索引相关的文档,true:表示如果索引不存在,直接返回false,不报错
        client.dropIndex(true);
    }

    /**
     * 删除文档数据
     */
    public void deleteDocuments(String ...docs){
        // 传入一组(将删除的文档ID)
        client.deleteDocuments(true,docs);
    }

    /**修改文档**/
    public void updateDocument(String docId, double score, Map map){
        client.updateDocument(docId,score,map);
    }

    /**添加数据8**/
    public boolean addHashData(){
        try{
            // FullText类型(全文查询)
            Schema.Field storeName = new Schema.Field("storeName", Schema.FieldType.FullText,false);
            Schema.Field storeIntroduce = new Schema.Field("storeIntroduce", Schema.FieldType.FullText,false);
            // tag类型
            Schema.Field tag = new Schema.Field("tag", Schema.FieldType.Tag,false);
            // geo类型,经纬度
            Schema.Field location = new Schema.Field("location", Schema.FieldType.Geo,false);
            // number类型(此类型可以范围查询),true:允许排序
            Schema.Field start = new Schema.Field("start", Schema.FieldType.Numeric,true);

            // 定义一个索引模式(相当于student的表结构)
            Schema schema = new Schema()
                    .addField(storeName)
                    .addField(storeIntroduce)
                    .addField(tag)
                    .addField(location)// 加上Geo类型后,无法查询出数据,暂时不知道什么原因
                    .addField(start);


            // 创建索引(如果存在相同的索引则会创建失败)
            client.createIndex(schema, Client.IndexOptions.Default());

            // 创建一些map数据,准备存入student索引
            Map<String, Object> fields1 = createDocument("粥铺", "我家小米粥好喝", "满减"
                    ,new GeoValue(106.555697,29.613248,5000, GeoValue.Unit.METERS),300);

            Map<String, Object> fields2 = createDocument("米铺", "我家米便宜好吃", "香米"
                    ,new GeoValue(106.555661,29.613695,100, GeoValue.Unit.METERS),100);

            Map<String, Object> fields3 = createDocument("米通信", "电子批发城", "电子"
                    ,new GeoValue(106.555922,29.613429,100, GeoValue.Unit.METERS),120);

            Map<String, Object> fields4 = createDocument("熊猫家居", "只为让你有更好的舒适生活", "家居"
                    ,new GeoValue(106.555922,29.613429,100, GeoValue.Unit.METERS),220);

            Map<String, Object> fields5 = createDocument("河马家居", "为你私人定制", "家居"
                    ,new GeoValue(106.555571,29.612973,100, GeoValue.Unit.METERS),60);


            // 创建选项,设置语言为中文,否则无法进行中文分词查询
            AddOptions options = new AddOptions();
            options.setLanguage("chinese");

        /*
            创建文档(相当于表的每一行数据)id:"doc1"   fields:fields1  score:1
                id:唯一值,否则创建失败,且必须为string;
                fields:需要存放的数据(默认为Map类型);
                score:分数(权重0~1)
         */
            Document doc1 = new Document("doc1", fields1,1);
            Document doc2 = new Document("doc2", fields2,0.7);
            Document doc3 = new Document("doc3", fields3,0.5);
            Document doc4 = new Document("doc4", fields4,0.3);
            Document doc5 = new Document("doc5", fields5,0.1);

            // 添加文档,将设置项加进去
            client.addDocument(doc1,options);
            client.addDocument(doc2,options);
            client.addDocument(doc3,options);
            client.addDocument(doc4,options);
            client.addDocument(doc5,options);
        }catch (Exception e){
            e.printStackTrace();
            log.info("文档添加失败!");
            return false;
        }
        log.info("文档添加成功!");
        return true;
    }

    /**根据关键字全文查询
     *  @method limit(0,3) 从位置0开始查询出3条
     *  @method setWithScores() 按分数大小查询(权重),从大到小排
     *  @method setLanguage("chinese") 默认不支持中文分词,所以要设置语言
     *  @method highlightFields("title","body") 设置哪些字段需要高亮显示
     */
    public SearchResult searchByKey(String queryString) {

        // 创建查询语句
        Query query = new Query(queryString)
                .limit(0,3)
                .setWithScores()
                .highlightFields("storeName","storeIntroduce")
                .setLanguage("chinese");

        // 提交查询
        SearchResult result = client.search(query);
        // 输出
        show(result);
        return result;
    }

    /**根据数值范围+key查询
     *
     * @method addFilter()
     *      添加过滤器
     * @method Query.NumericFilter(field,min,max)
     *      数值过滤器
     *      查询字段field范围(min,max)
     * **/
    public SearchResult searchByNumberRange(String key, String field, int min, int max){

        Query query = new Query(key)
                .addFilter(new Query.NumericFilter(field,min,max))
                .limit(0,3)
                .setLanguage("chinese");
        // 提交查询
        SearchResult result = client.search(query);
        // 输出
        show(result);
        return result;
    }

    /**位置范围+key查询
     * new Query.GeoFilter("location",lon,lat,radius,unit)
     *      经纬度过滤器
     * @param key 搜索关键词
     * @param lon 经度
     * @param lat 纬度
     * @param radius 半径
     * @param unit 度量单位
     * **/
    public SearchResult searchByGeoRange(String key, double lon, double lat, double radius, String unit){
        Query query = new Query(key)
                .addFilter(new Query.GeoFilter("location",lon,lat,radius,unit))
                .limit(0,3)
                .setLanguage("chinese");
        // 提交查询
        SearchResult result = client.search(query);

        show(result);
        return result;
    }

    /**
     * 聚合查询
     * @param query
     * @param start
     * @param state
     * @param avgprice
     * @param k
     * @return
     */
    public AggregationResult aggregate(String query, String start, String state, String avgprice, String k){
        AggregationBuilder builder =new AggregationBuilder(query)
                .apply("@".concat(start).concat("/1000"), k)
                .groupBy("@".concat(state), Reducers.avg("@".concat(k)).as(avgprice))
                .filter("@".concat(avgprice).concat(">=2"))
                .sortBy(Integer.MAX_VALUE, SortedField.asc("@".concat(state)));
        return client.aggregate(builder);
    }

    private static Map<String, Object> createDocument(String storeName, String storeIntroduce,
                                                      String tag, GeoValue location, Integer start){

        Map<String, Object> fields = new HashMap<>();

        fields.put("storeName", storeName);
        fields.put("storeIntroduce", storeIntroduce);
        fields.put("tag", tag);
        fields.put("location", location);
        fields.put("start", start);

        return fields;
    }

    public static void show(SearchResult searchResult){
        // 输出
        searchResult.docs.stream().forEach(System.out::println);
    }

lettuceMod

 private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private RedisModulesClient client;

    /**
     * 创建索引 hash
     * @throws Exception
     */
    @PostMapping("/createIndex")
    public void createIndex() throws Exception {

        StatefulRedisModulesConnection<String, String> connection = client.connect();

        RedisModulesCommands<String, String> commands = connection.sync();
        String s = commands.ftCreate("beers", CreateOptions.<String, String>builder().on(CreateOptions.DataType.HASH).prefix("docs:").build(),
                Field.text("name").build());

        System.out.println(s);
    }

    /**
     * 删除索引
     */
    @PostMapping("/deleteIndex")
    public String deleteIndex(){
        StatefulRedisModulesConnection<String, String> connection = client.connect();

        RedisModulesCommands<String, String> commands = connection.sync();
        commands.ftDropindex("beers");
        return "索引删除成功";
    }

    /**
     * 新增数据
     */
    @PostMapping("/insertDataByHash")
    public String insertDataByHash(){

        StatefulRedisModulesConnection<String, String> connection = client.connect();

        RedisModulesCommands<String, String> commands = connection.sync();
        Map<String,String> map = new HashMap<>(2);
        map.put("name","dog");
        String hmset = commands.hmset("docs:2", map);
        return hmset;
    }

    /**
     * 搜索数据
     */
    @PostMapping("/searchData")
    public SearchResults searchData(){
        StatefulRedisModulesConnection<String, String> connection = client.connect();

        RedisModulesCommands<String, String> commands = connection.sync();

        SearchResults<String, String> documents = commands.ftSearch("beers", "*");

        return documents;
    }

redisson

@Autowired
    RedissonClient redisson;

    /**
     * 创建索引 hash类型
     */
    @PostMapping("/creatHashIndex")
    public String creatHashIndex(){


        RSearch s = redisson.getSearch();

        try {

            s.createIndex("idx", IndexOptions.defaults()
                            .on(IndexType.HASH)
                            .prefix(Arrays.asList("doc:")),
                    FieldIndex.text("v1"),
                    FieldIndex.text("v2"));

        }catch (Exception e){
            String message = e.getMessage();
            if(message.contains("Index already exists")){
                return "该索引已存在,请勿重复创建";
            }
            return "创建索引异常";

        }


        return "创建索引成功";
    }
    /**
     * 创建索引 json类型
     */
    @PostMapping("/creatJsonIndex")
    public String creatJsonIndex(){


        RSearch s = redisson.getSearch(StringCodec.INSTANCE);

        try {

            s.createIndex("idx", IndexOptions.defaults()
                            .on(IndexType.JSON)
                            .prefix(Arrays.asList("doc:")),
                    FieldIndex.numeric("$..arr").as("arr"),
                    FieldIndex.text("$..value").as("val"));

        }catch (Exception e){
            String message = e.getMessage();
            if(message.contains("Index already exists")){
                return "该索引已存在,请勿重复创建";
            }
            return "创建索引异常";

        }


        return "创建索引成功";
    }


    /**
     * 删除索引
     */
    @PostMapping("/dropIndex")
    public String dropIndex(){

        redisson.getSearch().dropIndex("idx");

        return "OK";
    }


    /**
     * 新增数据 hash类型
     * @return
     */
    @PostMapping("/insertDataByHash")
    public String insertDataByHash(){

        //rmap格式
        RMap<String, SimpleObject> m = redisson.getMap("doc:1", new CompositeCodec(StringCodec.INSTANCE, redisson.getConfig().getCodec()));
        m.put("v1", new SimpleObject("name1"));
        m.put("v2", new SimpleObject("name2"));
        RMap<String, SimpleObject> m2 = redisson.getMap("doc:2", new CompositeCodec(StringCodec.INSTANCE, redisson.getConfig().getCodec()));
        m2.put("v1", new SimpleObject("name3"));
        m2.put("v2", new SimpleObject("name4"));


        return "OK";
    }
    /**
     * 新增数据
     * @return
     */
    @PostMapping("/insertDataByJson")
    public String insertDataByJson(){

        RJsonBucket<TestClass> b = redisson.getJsonBucket("doc:1", new JacksonCodec<>(TestClass.class));
//        b.trySet(new TestClass(Arrays.asList(1, 2, 3), "hello"));
//        boolean hello = b.setIfAbsent(new TestClass(Arrays.asList(1, 2, 3), "hello"));
//        boolean hello = b.setIfExists(new TestClass(Arrays.asList(1, 2, 3), "hello"));
        b.set(new TestClass(Arrays.asList(1, 2, 3), "hello"));


        return "新增成功";
    }

    /**
     * 查询数据 hash
     * @return
     */
    @PostMapping("/searchDataByHash")
    public SearchResult searchDataByHash(){


        RSearch s = redisson.getSearch();

        SearchResult r = s.search("idx", "*", QueryOptions.defaults()
                .returnAttributes(new ReturnAttribute("v1"), new ReturnAttribute("v2")));

        return r;
    }
    /**
     * 查询数据 json
     * @return
     */
    @PostMapping("/searchDataByJson")
    public SearchResult searchDataByJson(){

        RSearch s = redisson.getSearch(StringCodec.INSTANCE);

        SearchResult r = s.search("idx", "*", QueryOptions.defaults()
                .returnAttributes(new ReturnAttribute("arr"), new ReturnAttribute("val")));

        return r;
    }

    /**
     * Aggregation聚合查询
     */
    @PostMapping("/searchAggregationDataByHash")
    public AggregationResult searchAggregationDataByHash(){


        RSearch s = redisson.getSearch();

        AggregationResult r = s.aggregate("idx", "*", AggregationOptions.defaults()
                .load("v1", "v2"));

        return r;
    }
    /**
     * 查询数据 json
     * @return
     */
    @PostMapping("/searchAggregationDataByJson")
    public AggregationResult searchAggregationDataByJson(){

        RSearch s = redisson.getSearch(StringCodec.INSTANCE);

        AggregationResult r = s.aggregate("idx", "*", AggregationOptions.defaults()
                .load("arr", "val"));

        return r;
    }

    /**
     * 拼写检查
     * FT. SPELLCHECK返回一个数组回复,其中每个元素代表查询中的一个拼写错误的术语。
     * 拼写错误的术语按其在查询中出现的顺序排序。
     * 每个拼写错误的术语依次是一个3元素数组,由常量字符串TERM、术语本身和拼写更正建议数组组成。
     * 拼写更正数组中的每个元素由建议的分数和建议本身组成。
     * 每个拼写错误的术语的建议数组按分数降序排列。
     * 分数的计算方法是将建议术语存在的文档数量除以索引中的文档总数。
     * 结果可以通过将分数除以最高分来归一化。
     */
    @PostMapping("/spellCheck")
    public Map<String, Map<String, Double>> spellCheck(){

        RSearch s = redisson.getSearch();


        long l = s.addDict("name", "hockey", "stik");

        Map<String, Map<String, Double>> res = s.spellcheck("idx", "hocke sti", SpellcheckOptions.defaults()
                .includedTerms("name").distance(2));

        return res;
    }

redis-spring-search

 @Autowired
    StatefulRediSearchConnection statefulRediSearchConnection;


    /**
     * 创建索引
     */
    @PostMapping("/createIndex")
    public String createIndex(){

        RediSearchCommands sync = statefulRediSearchConnection.sync();
        sync.create("pools",
                CreateOptions.builder().on(CreateOptions.Structure.HASH).prefix("beer:").build(),
                new Field.Text("name"));
        return "索引创建成功";
    }

    /**
     * 删除索引
     */
    @PostMapping("/dropIndex")
    public String dropIndex(){
        RediSearchCommands sync = statefulRediSearchConnection.sync();
        String pools = sync.dropIndex("pools");
        return pools;
    }

    /**
     * 新增数据
     * @return
     */
    @PostMapping("/insertDataHash")
    public Long insertDataHash(){

        RediSearchCommands sync = statefulRediSearchConnection.sync();
        Map<String,String > map = new HashMap<>(2);
        map.put("name","xiaobai");
        Long hset = sync.hset("beer:11", map);
        return hset;
    }

    /**
     * 搜索数据
     */
    @PostMapping("/searchData")
    public SearchResults searchData(){

        RediSearchCommands sync = statefulRediSearchConnection.sync();
        SearchResults pools = sync.search("pools", "xiaobai Schifrin");

        return pools;
    }

到了这里,关于Redis新功能 RedisSearch安装和使用 媲美ES的存在的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】C++11 -- 新功能

    在C++11之前一个类有6个默认成员函数,在C++11标准中又新增了两个默认成员函数,分别是移动构造函数和移动赋值函数 默认移动构造和移动赋值生成的条件 移动构造函数的生成条件:没有自己实现移动构造函数,并且没有自己实现析构函数,拷贝构造函数和拷贝赋值函数 移

    2024年02月17日
    浏览(47)
  • Midjourney新功能:角色参照指南

    基本概念 角色参照(Character Reference) :这个功能允许用户在不同的图像生成中保持给定参照角色的一致性。 适用模型 :适用于Midjourney V6和Niji6型号。 功能亮点 跨风格一致性 :可以在不同风格(如动漫风、写实风)中保持角色特征一致。 面部、着装、发型调控 :用户可以

    2024年04月10日
    浏览(57)
  • TypeScript 5.1发布,新功能更新

    1:返回类型增加undefined 这里设置了一个别名 fun,当时使用它的时候,我们必须显示返回一个 undefined 。 现在你可以直接设置返回类型: 而不仅限于 void any 。 4.3版本 :❌ 5.1版本 :✅ 2:getter可以设置和 setter 的不相关类型 在之前版本 ,get 返回类型应该为 set 的子类型,如

    2024年02月09日
    浏览(47)
  • SOLIDWORKS 2023新功能揭秘(一):3D CAD功能的十大更新

    SolidWorks 3D CAD  软件拥有设计、模拟、成本估算、可制造性检查、CAM、可持续设计和数据管理等功能,同时还包含适用于钣金,焊件,曲面,模具,产品配置,DFM和CAM的专业工具,支持ECAD/MCAD协作,复杂的零部件库以及高级真实感渲染。更重要的是具有结构和运动分析功能,

    2024年02月05日
    浏览(46)
  • 三星泄露微软 Copilot 新功能:用自然语言操控各种功能

    3 月 11 日消息,微软计划本月晚些时候发布新款 Surface 电脑和适用于 Windows 11 的 Copilot 新功能,但三星似乎等不及了,在其即将推出的 Galaxy Book4 系列产品宣传材料中泄露了一些即将到来的 Copilot 功能。 三星官网上发布的图片证实了此前关于微软正为其人工智能助手 Copilo

    2024年04月09日
    浏览(83)
  • C# 12 预览版的新功能

    作者:Kathleen Dollard 排版:Alan Wang Visual Studio 17.7 Preview 3 和 .NET 8 Preview 6 的发布推进了 C# 12的发展。此预览版包含的功能为将来的性能增强奠定了基础。现在,您能够在库中更方便的使用内联函数。此预览版首次推出了一项实验性功能:拦截器。该功能允许生成器重新路由代

    2024年02月14日
    浏览(42)
  • 【C++】C++11类的新功能

    👀 樊梓慕: 个人主页  🎥 个人专栏: 《C语言》 《数据结构》 《蓝桥杯试题》 《LeetCode刷题笔记》 《实训项目》 《C++》 《Linux》 《算法》 🌝 每一个不曾起舞的日子,都是对生命的辜负 目录 前言 默认成员函数 类成员变量初始化 强制生成默认函数的default 禁止生

    2024年04月17日
    浏览(53)
  • Microsoft Releases .NET 7新功能

    Microsoft Visual Studio是一种统一的开发体验,使开发人员能够跨web、云和设备创建多层应用程序。11月8日,微软发布了该强大开发环境的下一版本:Visual Studio 2022 17.4版。 除了修复许多顶级报告的bug之外,17.4版还包括了许多基于开发者社区建议的新功能,包括: Visual Studio的本

    2024年02月06日
    浏览(45)
  • 揭密.NET 8到底有什么新功能

    .NET 8 是微软于2021年8月24日宣布的下一代编程语言和框架,它是 .NET 宇宙的一部分,与 C# (Common Language Infrastructure) 紧密集成。.NET 8 引入了许多新功能,如原生编译、值类型 (Value Types)、结构化并发 (structured concurrency) 和快速数组 (RapidArray)。.NET 8 还支持本机 (native) AOT (Ahead-Of

    2024年02月03日
    浏览(41)
  • Windows 12:发布日期、新功能、价格、硬件要求

    距离Windows 11首次发布仅一年时间,但关于 Windows 12 的传言已经开始四处流传。有报道称,微软正计划切换到Windows 的新更新周期,未来几个月将不会发布 Windows 11 23H2 或 24H2 版本。事实上,据报道Windows 11 23H2“太阳谷3”更新已经停止,Windows 12(代号:Next Valley)的工作已经开

    2024年02月04日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包