【知识积累】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");
    }

猜你喜欢

转载自blog.csdn.net/axin1240101543/article/details/109601899