根据匹配的关键词对过滤后的推文进行分类:Twitter4j API

12

我已经创建了一个按关键词过滤的Twitter流,如下所示。

TwitterStream twitterStream = getTwitterStreamInstance();
FilterQuery filtre = new FilterQuery();
String[] keywordsArray = { "iphone", "samsung" , "apple", "amazon"};
filtre.track(keywordsArray);
twitterStream.filter(filtre);
twitterStream.addListener(listener);

如何根据匹配的关键词对推文进行最佳分类。例如,所有与“iphone”匹配的推文应存储在“IPHONE”表中,所有与“三星”匹配的推文将存储在“SAMSUNG”表中,依此类推。注意:过滤关键词的数量约为500个。


你需要循环遍历关键词,并检查推文是否包含关键词。你将从Twitter获取一个单一的流,无法进行区分。 - Ramanan
是的,但这里的关键词匹配不仅仅基于简单比较!它是一种更复杂的搜索,因为关键词可能由多个单词组成。Twitter4j有一个称为“track”的方法,https://dev.twitter.com/streaming/overview/request-parameters#track用于过滤关键词匹配,考虑到许多参数。如果我找到了他们正在使用的搜索代码,那么我可以直接使用它。如果没有,那么我必须从头开始编写整个代码。 - Nicool
你说的“table”是指什么?是指MySQL中的表格吗? - sameera sy
@Nicool,将其放入表格中是什么意思? - sameera sy
是的,数据库表。主要目标是将推文映射到搜索词。 - ssc-hrep3
3个回答

1

以下是如何使用 StatusListener 来查询接收到的 Status 对象:

final Set<String> keywords = new HashSet<String>();
keywords.add("apple");
keywords.add("samsung");
// ...

final StatusListener listener = new StatusAdapter() {
    @Override
    public void onStatus(Status status) {
        final String statusText = status.getText();
        for (String keyword : keywords) {
            if (statusText.contains(keyword)) {
                dao.insert(keyword, statusText);
            }
        }
    }
};

final TwitterStream twitterStream = getTwitterStreamInstance();
final FilterQuery fq = new FilterQuery();
fq.track(keywords.toArray(new String[0]));
twitterStream.addListener(listener);
twitterStream.filter(fq);

我认为DAO的定义应该是:

public interface StatusDao {
    void insert(String tableSuffix, Status status);
}

您将会有一个与每个关键词对应的数据库表。实现将使用tableSuffix在正确的表中存储Status,sql 大致如下:
INSERT INTO status_$tableSuffix$ VALUES (...)

注意事项:

  1. 如果一条推文包含“苹果”和“三星”,则此实现将在多个表中插入一个状态

  2. 此外,这是一个相当天真的实现,您可能需要考虑将插入批处理到表中...但这取决于您将收到的推文数量。

  3. 正如评论中所指出的那样,API在匹配时考虑其他属性,例如URL和嵌入式推文(如果存在),因此仅搜索状态文本以进行关键字匹配可能不足够。


这只能部分地起作用,因为Twitter API不仅搜索推文,还会搜索转发的推文、扩展URL(它们在推文中被缩短)等等。我的当前解决方法已经包含了对推文和这些属性的搜索,但我不能确定是否已经搜索了所有相关属性。 - ssc-hrep3
在查找“特朗普”时的示例推文:“他错了。请参见:t.co/SOMELINK”。这里单词“特朗普”在链接内部,但推文仍然可以被Twitter找到。 - ssc-hrep3
1
我明白了,statusText.contains(keyword) 的保护条件不够充分,因为其他属性可能也包含您感兴趣的关键字。 - Jonathan

1
似乎唯一的方法是遍历Status对象的多个属性才能找出一条推文属于哪个关键词。以下代码需要一个具有insertTweet(String tweetText, Date createdAt, String keyword)方法的数据库服务,并且每条推文都会在数据库中存储多次,如果发现多个关键词。如果在推文文本中至少找到一个关键词,则不会搜索更多关键词的其他属性。
// creates a map of the keywords with a compiled pattern, which matches the keyword
private Map<String, Pattern> keywordsMap = new HashMap<>();
private TwitterStream twitterStream;
private DatabaseService databaseService; // implement and add this service

public void start(List<String> keywords) {
    stop(); // stop the streaming first, if it is already running

    if(keywords.size() > 0) {
        for(String keyword : keywords) {
            keywordsMap.put(keyword, Pattern.compile(keyword, Pattern.CASE_INSENSITIVE));
        }

        twitterStream = new TwitterStreamFactory().getInstance();
        StatusListener listener = new StatusListener() {
            @Override
            public void onStatus(Status status) {
                insertTweetWithKeywordIntoDatabase(status);
            }
            /* add the unimplemented methods from the interface */
        };
        twitterStream.addListener(listener);
        FilterQuery filterQuery = new FilterQuery();
        filterQuery.track(keywordsMap.keySet().toArray(new String[keywordsMap.keySet().size()]));
        filterQuery.language(new String[]{"en"});

        twitterStream.filter(filterQuery);
    }
    else {
        System.err.println("Could not start querying because there are no keywords.");
    }
}

public void stop() {
    keywordsMap.clear();
    if(twitterStream != null) {
        twitterStream.shutdown();
    }
}

private void insertTweetWithKeywordIntoDatabase(Status status) {
    // search for keywords in tweet text
    List<String> keywords = getKeywordsFromTweet(status.getText());

    if (keywords.isEmpty()) {
        StringBuffer additionalDataFromTweets = new StringBuffer();

        // get extended urls
        if (status.getURLEntities() != null) {
            for (URLEntity url : status.getURLEntities()) {
                if (url != null && url.getExpandedURL() != null) {
                    additionalDataFromTweets.append(url.getExpandedURL());
                }
            }
        }

        // get retweeted status -> text
        if (status.getRetweetedStatus() != null && status.getRetweetedStatus().getText() != null) {
            additionalDataFromTweets.append(status.getRetweetedStatus().getText());
        }
        // get retweeted status -> quoted status -> text
        if (status.getRetweetedStatus() != null && status.getRetweetedStatus().getQuotedStatus() != null
                && status.getRetweetedStatus().getQuotedStatus().getText() != null) {
            additionalDataFromTweets.append(status.getRetweetedStatus().getQuotedStatus().getText());
        }
        // get retweeted status -> quoted status -> extended urls
        if (status.getRetweetedStatus() != null && status.getRetweetedStatus().getQuotedStatus() != null
                && status.getRetweetedStatus().getQuotedStatus().getURLEntities() != null) {
            for (URLEntity url : status.getRetweetedStatus().getQuotedStatus().getURLEntities()) {
                if (url != null && url.getExpandedURL() != null) {
                    additionalDataFromTweets.append(url.getExpandedURL());
                }
            }
        }

        // get quoted status -> text
        if (status.getQuotedStatus() != null && status.getQuotedStatus().getText() != null) {
            additionalDataFromTweets.append(status.getQuotedStatus().getText());
        }
        // get quoted status -> extended urls
        if (status.getQuotedStatus() != null && status.getQuotedStatus().getURLEntities() != null) {
            for (URLEntity url : status.getQuotedStatus().getURLEntities()) {
                if (url != null && url.getExpandedURL() != null) {
                    additionalDataFromTweets.append(url.getExpandedURL());
                }
            }
        }

        String additionalData = additionalDataFromTweets.toString();
        keywords = getKeywordsFromTweet(additionalData);
    }

    if (keywords.isEmpty()) {
        System.err.println("ERROR: No Keyword found for: " + status.toString());

    } else {
        // insert into database
        for(String keyword : keywords) {
            databaseService.insertTweet(status.getText(), status.getCreatedAt(), keyword);
        }
    }

}

// returns a list of keywords which are found in a tweet
private List<String> getKeywordsFromTweet(String tweet) {
    List<String> result = new ArrayList<>();

    for (String keyword : keywordsMap.keySet()) {
        Pattern p = keywordsMap.get(keyword);
        if (p.matcher(tweet).find()) {
            result.add(keyword);
        }
    }

    return result;
}

0
嗯,你可以创建一个类,类似于ArrayList,但是使其能够创建一个ArrayList的数组,称之为TweetList。这个类将需要一个插入函数。
然后使用两个for循环来搜索推文,并找到包含在普通ArrayList中的匹配关键词,然后将它们添加到与关键词在关键词ArrayList中的索引相匹配的TweetList中。
 for (int i = 0; i < tweets.length; i++)
           {
               String[] split = tweets[i].split(" ");// split the tweet up
               for (int j = 0; j < split.length; j++)
                   if (keywords.contains(split[j]))//check each word against the keyword list
                       list[keywords.indexOf(j)].insert[tweets[i]];//add the tweet to the tree index that matches index of the keyword
           }

这仅能部分地运作,因为 Twitter API 不仅限于搜索推文,还包括转发的推文、扩展 URL(它们在推文本身中被缩短)等。我的当前解决方案已经包含了对推文和这些属性进行搜索,但我无法确定是否已搜索所有相关属性。 - ssc-hrep3
在查找“特朗普”时的示例推文:“他错了。请参见:t.co/SOMELINK”。这里,“特朗普”一词位于链接内,但推文仍然可以被Twitter找到。 - ssc-hrep3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接