【知识积累】RocketMQ-TAG、SQL表达式过滤

1、TAG过滤消费

在Producer中使用Tag:

Message msg = new Message("TopicTest","TagA" ,("Hello RocketMQ " ).getBytes(RemotingHelper.DEFAULT_CHARSET));

在Consumer中订阅Tag:

consumer.subscribe("TopicTest", "TagA||TagB");// * 代表订阅Topic下的所有消息

注:

  • 分组和tag要统一,不能随便改,但可以消费同一个topic;
  • 集群消息模式下,Producer生产了消息,只有一个consumer能够消费,这个consumer会把所有的消息拉回来,然后与tags相匹配的被消费(CONSUMED),不能够匹配的将被CONSUMED_BUT_FILTERED(消费并过滤掉);
  • 想要消费,那么需要换一个组来消费,即同一个组不能同时干两件事儿,又过滤又消费。
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("xxxx");
consumer.subscribe("myTopic002", "tag_aaa");

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("oooo");
consumer.subscribe("myTopic002", "tag_bbb");

2、TAG实战

2.1、生产者

public class Producer1 {

    public static void main(String[] args) throws MQClientException, RemotingException, InterruptedException, MQBrokerException {
        DefaultMQProducer producer = new DefaultMQProducer("xxoo");
        //设置name server地址
        producer.setNamesrvAddr("192.168.244.8:9876");
        producer.start();

        // topic 消息将要发送的地址
        // body 消息中具体的数据
        Message msg = new Message("myTopic003", "tag_aaa", "aaa", "aaa".getBytes());
        SendResult sendResult = producer.send(msg);
        System.out.println(sendResult);
        producer.shutdown();
    }

}
public class Producer2 {

    public static void main(String[] args) throws MQClientException, RemotingException, InterruptedException, MQBrokerException {
        DefaultMQProducer producer = new DefaultMQProducer("xxoo");
        //设置name server地址
        producer.setNamesrvAddr("192.168.244.8:9876");
        producer.start();

        // topic 消息将要发送的地址
        // body 消息中具体的数据
        Message msg = new Message("myTopic003", "tag_bbb", "bbb", "bbb".getBytes());
        SendResult sendResult = producer.send(msg);
        System.out.println(sendResult);
        producer.shutdown();
    }

}

2.2、消费者

public class Consumer1 {

    public static void main(String[] args) throws MQClientException {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("aaa");
        consumer.setNamesrvAddr("192.168.244.8:9876");

        //每个consumer关注一个topic
        //topic 关注的消息地址
        //过滤器 * 表示不过滤
        consumer.subscribe("myTopic003", "tag_aaa");

        //注册监听器
        consumer.registerMessageListener(new MessageListenerConcurrently(){

            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
                list.forEach(message -> {
                    byte[] body = message.getBody();
                    System.out.println(new String(body));
                });
                // 返回一个消费状态 CONSUME_SUCCESS:消费成功 RECONSUME_LATER:稍后重新推送消费
                // 默认情况下 只会被一个consumer消费到 点对点消费
                // ack -> acknowledge
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        /**
         * 集群: 一组consumer中一个消费就可以了,失败会重投,不保证重投到原来的consumer,消费状态由broker维护
         * 广播: 每个consumer都能消费,失败不会重投,消费状态由consumer维护
         */
        consumer.setMessageModel(MessageModel.CLUSTERING);
        consumer.start();
        System.out.println("consumer1 started");
    }

}
public class Consumer2 {

    public static void main(String[] args) throws MQClientException {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("bbb");
        consumer.setNamesrvAddr("192.168.244.8:9876");

        //每个consumer关注一个topic
        //topic 关注的消息地址
        //过滤器 * 表示不过滤
        consumer.subscribe("myTopic003", "tag_bbb");

        //注册监听器
        consumer.registerMessageListener(new MessageListenerConcurrently(){

            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
                list.forEach(message -> {
                    byte[] body = message.getBody();
                    System.out.println(new String(body));
                });
                // 返回一个消费状态 CONSUME_SUCCESS:消费成功 RECONSUME_LATER:稍后重新推送消费
                // 默认情况下 只会被一个consumer消费到 点对点消费
                // ack -> acknowledge
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        /**
         * 集群: 一组consumer中一个消费就可以了,失败会重投,不保证重投到原来的consumer,消费状态由broker维护
         * 广播: 每个consumer都能消费,失败不会重投,消费状态由consumer维护
         */
        consumer.setMessageModel(MessageModel.CLUSTERING);
        consumer.start();
        System.out.println("consumer2 started");
    }

}

2.3、测试结果

 

3、SQL表达式过滤(默认关闭)

3.1、优势

比tag粒度更细的过滤,消费者将收到包含TAGA或TAGB或TAGB的消息. 但限制是一条消息只能有一个标签,而这对于复杂的情况可能无效。 在这种情况下,您可以使用SQL表达式筛选出消息.。

3.2、语法

RocketMQ只定义了一些基本的语法来支持这个功能。 你也可以很容易地扩展它.

  1. 数字比较, 像 >, >=, <, <=, BETWEEN, =;
  2. 字符比较, 像 =, <>, IN;
  3. IS NULL 或者 IS NOT NULL;
  4. 逻辑运算AND, OR, NOT;

常量类型是:

  1. 数字, 像123, 3.1415;
  2. 字符串, 像‘abc’,必须使用单引号;
  3. NULL, 特殊常数;
  4. 布尔常量, TRUE 或FALSE;

3.3、使用

ArrayList<Message> msgs = new ArrayList<>();
for (int i = 0; i < 100; i++) {
    // topic 消息将要发送的地址
    // body 消息中具体的数据
    Message msg = new Message("myTopic003", "tag_aaa", "aaa", ("aaa" + i).getBytes());
    //消息的属性为age,一共100条消息, age为1-100
    msg.putUserProperty("age", String.valueOf(i));
    msgs.add(msg);
}
SendResult sendResult = producer.send(msgs);
//过滤年龄大于等于18小于等于38的消息
MessageSelector messageSelector = MessageSelector.bySql("age >= 18 and age <= 38");
//每个consumer关注一个topic
//topic 关注的消息地址
//过滤器 * 表示不过滤
consumer.subscribe("myTopic003", messageSelector);

4、SQL表达式过滤实战

4.1、开启

vi broker.cof
enablePropertyFilter=true
../bin/mqbroker -n 192.168.150.113:9876 -c broker.conf 

4.2、生产者

public class Producer {

    public static void main(String[] args) throws MQClientException, RemotingException, InterruptedException, MQBrokerException {
        DefaultMQProducer producer = new DefaultMQProducer("xxoo");
        //设置name server地址
        producer.setNamesrvAddr("192.168.244.8:9876");
        producer.start();

        ArrayList<Message> msgs = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            // topic 消息将要发送的地址
            // body 消息中具体的数据
            Message msg = new Message("myTopic003", "tag_aaa", "aaa", ("aaa" + i).getBytes());
            //消息的属性为age,一共100条消息, age为1-100
            msg.putUserProperty("age", String.valueOf(i));
            msgs.add(msg);
        }
        SendResult sendResult = producer.send(msgs);
        System.out.println(sendResult);
        producer.shutdown();
    }

}

4.3、消费者

public class Consumer {

    public static void main(String[] args) throws MQClientException {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("aaa");
        consumer.setNamesrvAddr("192.168.244.8:9876");

        //过滤年龄大于等于18小于等于38的消息
        MessageSelector messageSelector = MessageSelector.bySql("age >= 18 and age <= 38");
        //每个consumer关注一个topic
        //topic 关注的消息地址
        //过滤器 * 表示不过滤
        consumer.subscribe("myTopic003", messageSelector);

        //注册监听器
        consumer.registerMessageListener(new MessageListenerConcurrently(){

            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
                list.forEach(message -> {
                    byte[] body = message.getBody();
                    System.out.println(new String(body));
                });
                // 返回一个消费状态 CONSUME_SUCCESS:消费成功 RECONSUME_LATER:稍后重新推送消费
                // 默认情况下 只会被一个consumer消费到 点对点消费
                // ack -> acknowledge
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        /**
         * 集群: 一组consumer中一个消费就可以了,失败会重投,不保证重投到原来的consumer,消费状态由broker维护
         * 广播: 每个consumer都能消费,失败不会重投,消费状态由consumer维护
         */
        consumer.setMessageModel(MessageModel.CLUSTERING);
        consumer.start();
        System.out.println("consumer1 started");
    }

 

Spring Boot整合RocketMQ通常通过Apache RocketMQ的客户端API,如rocketmq-client-java库来操作消息队列。如果你想要按照时间范围查询普通消息、重试消息或死信消息,可以参考以下步骤: 1. 首先,在你的项目中添加rocketmq-tools依赖。由于提到的是`rocketmq-tools:5.3.0api`,这可能是一个特定版本的工具包,你可以通过Maven或Gradle将其添加到你的build.gradle文件中(Maven示例): ```groovy dependencies { implementation 'org.apache.rocketmq:rocketmq-tools:5.3.0' } ``` 2. 创建一个配置类,例如`RocketMQConfig`,用于存储 RocketMQ 的连接信息: ```java @Configuration public class RocketMQConfig { @Value("${rocketmq.brokerAddress}") private String brokerAddress; // 其他配置属性如 consumerGroup等 @Bean public DefaultMQProducer producer() { DefaultMQProducer producer = new DefaultMQProducer("your-consumer-group"); producer.setNamesrvAddr(brokerAddress); return producer; } } ``` 3. 使用`DefaultMessageQueueSelector`或自定义`MessageSelector`来指定查询的时间范围。比如,假设你想基于生产日期查询,你可以创建一个方法来获取满足条件的消息: ```java import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; import org.apache.rocketmq.client.consumer.MessageSelector; public class MessageQueryService { @Autowired private DefaultMQPushConsumer consumer; public List<Message> getMessagesByTimeRange(Date startDate, Date endDate) { // 创建一个消息选择器,这里以生产日期为例 MessageSelector selector = (message) -> message.getBornTimestamp() >= startDate.getTime() && message.getBornTimestamp() <= endDate.getTime(); // 查询消息 Map<String, QueueMessageGroupOffset> queueOffsets = consumer.fetchQueueOffset("your-topic", "your-tag", selector); List<Message> messages = new ArrayList<>(); for (String queue : queueOffsets.keySet()) { messages.addAll(queueOffsets.get(queue).getQueueMessages()); } return messages; } } ``` 请注意,上述代码示例假定你已经设置好消费者,并且Topic和Tag匹配了你需要查询的消息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值