在处理近乎庞大的数据集时加快QSortFilterProxyModel过滤
在此之前,我询问a question
关于我们需要表示多个列过滤,以表示适合多个过滤器模式的行。在处理近乎庞大的数据集时加快QSortFilterProxyModel过滤
现在,当处理大表(通过big
我的意思是大约200,000行和4列),如果我们有一个大的表(通常这是过滤器模式的前2个字符中最差),过滤会变得很慢。
那么你对此有何建议?
注:我有自己的高性能源数据模型基于this
例如巫喂约1秒
编辑1
我的该行数的视场改变我的方法(而不是QStandardItemModel
)从这个:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const {
if (/* filtering is enable*/) {
bool _res = sourceModel()->data(sourceModel()->index(source_row, 0, source_parent)).toString().contains(/*RegExp for column 0*/);
for (int col = 0; col < columnCount(); col++) {
_res &= sourceModel()->data(sourceModel()->index(source_row, col + 1, source_parent)).toString().contains(/*RegExp for column col + 1*/);
}
return _res;
}
return true;
}
要这样:
bool DataFilter::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const {
if (_enable) {
return (sourceModel()->index(source_row, 0, source_parent.child(source_row, 0)).data().toString().contains(/*string for column 0*/))
&& sourceModel()->index(source_row, 1, source_parent.child(source_row, 1)).data().toString().contains(/*string for column 1*/))
&& sourceModel()->index(source_row, 2, source_parent.child(source_row, 2)).data().toString().contains(/*string for column 2*/))
&& sourceModel()->index(source_row, 3, source_parent.child(source_row, 3)).data().toString().contains(/*string for column 3*/));
}
return true;
}
查找工作Perfect.Now过滤工作就像一个魅力无延迟
如果项目的数量是非常高的,你不能一次性加载它们,你可以尝试分批只有当添加项目他们需要在视图中。这可以通过覆盖canFetchMore()
和fetchMore()
来完成。看看Fetch More Example。请注意,这是QSqlQueryModel
从数据库内部加载大型模型的方式,请参阅here。
下面是你的模型可以使用这种方法来实现:
#include <QApplication>
#include <QtWidgets>
class MyTableModel : public QAbstractTableModel{
public:
explicit MyTableModel(int rowCount, QObject* parent=nullptr)
:QAbstractTableModel(parent),currentRowCount(0),wholeRowCount(rowCount){}
~MyTableModel(){}
int rowCount(const QModelIndex &parent) const override{
if(parent.isValid()) return 0;
return currentRowCount;
}
int columnCount(const QModelIndex &parent) const override{
if(parent.isValid()) return 0;
return 2;
}
QVariant data(const QModelIndex &index, int role) const override{
Q_ASSERT(index.row()<currentRowCount);
QVariant val;
if(role== Qt::DisplayRole || role== Qt::EditRole){
switch(index.column()){
case 0:
val= QString("#%1").arg(index.row()+1, 8, 10, QChar('0'));
break;
case 1:
val= rows[index.row()];
break;
}
}
return val;
}
bool canFetchMore(const QModelIndex &parent) const override{
if(parent.isValid()) return false;
return (currentRowCount < wholeRowCount);
}
void fetchMore(const QModelIndex& /* index */) override{
int toFetch= qMin(52, wholeRowCount-currentRowCount);
char ch = 'A';
beginInsertRows(QModelIndex(), currentRowCount, currentRowCount+toFetch-1);
for(int i=0; i<toFetch; i++){
rows+= QString(QChar(ch));
if(ch == 'Z') ch = 'A';
else ch++;
}
currentRowCount+= toFetch;
endInsertRows();
}
private:
int currentRowCount;
int wholeRowCount;
QStringList rows;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QVBoxLayout layout(&w);
QLineEdit filterLineEdit;
QTableView tableView;
layout.addWidget(&filterLineEdit);
layout.addWidget(&tableView);
MyTableModel model(200000);
QSortFilterProxyModel proxyModel;
proxyModel.setSourceModel(&model);
proxyModel.setFilterKeyColumn(-1);
tableView.setModel(&proxyModel);
QObject::connect(&filterLineEdit, &QLineEdit::textChanged, [&](){
proxyModel.setFilterFixedString(filterLineEdit.text());
});
w.show();
return a.exec();
}
如果你确定你真正的瓶颈是过滤,你可能还需要通过@DmitrySazonov,子类QSortFilterProxyModel
注意避免使用正则表达式,覆盖filterAcceptsRow()
并提供您的算法,而不是使用基于通用QRegExp
的过滤器。
要考虑的另一件事是避免在筛选器变窄时检查已经过滤的行,看看this question。
我很欣赏你的答案。但我很确定我的模型运行良好,我实现了快速的内部结构,并且我可以在一秒内载入200k行(在'release'配置中)。在此期间,我将显示一个不需要分页的进度条。我现在的问题是使用'QSortFilterProxyModel'实时过滤。请您解释一下关于'算法而不是基于QRegExp的过滤器'是不是比较字符串? – IMAN4K
如何在此期间显示进度栏?如果您的模型正在主线程中加载,则在控制返回到事件循环(加载完成时)之前,无法更新进度栏。我认为你做错了什么。 – Mike
@ IMAN4K,我的意思是为'filterAcceptsRow()'提供一个自定义的实现,它不依赖于正则表达式(相反,由于您的特定类型的过滤,它的效果更好)。不过,我真的认为Qt中的正则表达式已经很好地优化了,除非您确定您的过滤具有与正常字符串/正则表达式匹配不同的特定需求,否则您不应该这样做。 – Mike
1.剖析模型性能。 2.不要使用正则表达式进行过滤,编写自己的方法。 3.如果您确实需要大数据支持 - 请将内存中的SQLite作为模型和过滤的来源。 –
您可以抛弃QSortFilterProxyModel并将其替换为您自己的专用构建实现;由于您知道您的应用程序的特定需求,因此您可能可以将您的实现设计为比QSortFilterProxyModel更高效,而QSortFilterProxyModel必须是通用的,并且不能对与其交互的代码的行为作出任何假设。 –
@ JeremyFriesner.So你说我们应该忘记'QSortFilterProxyModel'.如果我们只需要过滤,在源数据模型(从QAbstractTableModel派生)中实现过滤是否是个好主意?如果没有,我会听你的建议。 – IMAN4K