[英]Best/efficient way to search a large csv in Java
我有一個帶有1.5K條目的較大的csv文件。 每個條目代表一個具有名稱,緯度和經度的全球城市。 在Java中搜索csv的最佳最快方法是什么? 我想用所有條目填充ArrayList,但我認為它很慢(除非我錯了)。 沒有這個文件不會增加大小,幾乎是100KB。 我希望能夠輸入城市名稱並更新搜索結果; 但是我可以自己弄清楚。
一個約1 MB的1.5K條目文件應花費數十毫秒。 一個1 GB的文件可能會花費數十秒,因此值得為該文件保存一個索引,以免每次都要重新讀取它。
您可以加載到地圖中以按name
索引
您可以通過NavigableMap添加經緯度索引。 這將加快按位置的查找。
一次加載文件需要一點時間,但是每次從磁盤讀取文件的速度要慢得多。
順便說一句,您可以擁有100 TB的數據和數萬億的行,要在Java中使用此數據,就必須發揮創造力。
簡而言之,如果它比您的內存少得多,則它是相對較小的文件。
1.5K行的城市名稱,緯度和經度並不是一個很大的文件,它是一個很小的文件 ,只要您不做任何完全不合理的事情(例如閱讀),那么閱讀它就無關緊要使用無緩沖的I / O每次一次一個字節。
因此,我要做的就是繼續讀取文件一次,構造行對象,並將它們添加到ArrayList
。 這可能足夠快,您可以在每次搜索后丟棄該列表,並在每次要搜索時重新加載它。 或者,如果您不介意占用一些內存,那么您當然想保留它。
但是無論如何,如果出於某種不可思議的原因最終導致性能問題,我只會擔心性能。 您尚未告訴我們您所生產產品的性能要求是什么。 沒有性能要求,也沒有度量標准,所有談論性能通常都是不合理的擔心,並且往往會導致過早的優化。
處理大型文本內容時,可能需要進行一些文本操作。
注意字符串連接。 通常使用StringBuffer
或StringBuilder
連接字符串。
最快的CSV解析器將是univocity-parsers 。 有很多方法可以解決此問題,以下方法足夠靈活,可以以不錯的速度為您提供結果。 以下示例使用具有130萬行的150MB CSV文件,並在大約1秒鍾內運行搜索:
RowProcessor
在這里,我們擴展了庫附帶的現有庫之一,
public class CsvSearch extends RowListProcessor {
//value to be searched for
private final String stringToMatch;
//name of column to match (if you don't have headers)
private final String columnToMatch;
//position of column to match
private int indexToMatch = -1;
public CsvSearch(String columnToMatch, String stringToMatch){
this.columnToMatch = columnToMatch;
this.stringToMatch = stringToMatch.toLowerCase(); //lower case to make the search case-insensitive
}
public CsvSearch(int columnToMatch, String stringToMatch){
this(stringToMatch, null);
this.indexToMatch = columnToMatch;
}
@Override
public void rowProcessed(String[] row, ParsingContext context) {
if(indexToMatch == -1) {
//initializes the index to match
indexToMatch = context.indexOf(columnToMatch);
}
String value = row[indexToMatch];
if(value != null && value.toLowerCase().contains(stringToMatch)) {
super.rowProcessed(row, context); // default behavior of the RowListProcessor: add the row into a List.
}
// else skip the row.
}
}
// let's measure the time roughly
long start = System.currentTimeMillis();
CsvParserSettings settings = new CsvParserSettings();
settings.setHeaderExtractionEnabled(true); //extract headers from the first row
CsvSearch search = new CsvSearch("City", "Paris");
//We instruct the parser to send all rows parsed to your custom RowProcessor.
settings.setProcessor(search);
//Finally, we create a parser
CsvParser parser = new CsvParser(settings);
//And parse! All rows are sent to your custom RowProcessor (CsvSearch)
//I'm using a 150MB CSV file with 1.3 million rows.
parser.parse(new File("/tmp/data/worldcitiespop.txt"));
//get the collected rows from our processor
List<String[]> results = search.getRows();
//Nothing else to do. The parser closes the input and does everything for you safely. Let's just get the results:
System.out.println("Rows matched: " + results.size());
System.out.println("Time taken: " + (System.currentTimeMillis() - start) + " ms");
這在我的計算機(2015 MacBook Pro)上產生了以下輸出:
Rows matched: 218
Time taken: 997 ms
返回的結果如下所示:
[af, parisang, Parisang, 08, null, 33.180704, 67.470836]
[af, qaryeh-ye bid-e parishan, Qaryeh-ye Bid-e Parishan, 06, null, 33.242727, 63.389834]
[ar, parish, Parish, 01, null, -36.518335, -59.633313]
[at, parisdorf, Parisdorf, 03, null, 48.566667, 15.85]
[au, paris creek, Paris Creek, 05, null, -35.216667, 138.8]
[az, hayi paris, Hayi Paris, 21, null, 40.449626, 46.55542]
[az, hay paris, Hay Paris, 21, null, 40.449626, 46.55542]
[az, rousi paris, Rousi Paris, 21, null, 40.435789, 46.510691]
[az, rrusi paris, Rrusi Paris, 21, null, 40.435789, 46.510691]
[bb, parish land, Parish Land, 01, null, 13.0666667, -59.5166667]
... (and many more)
如果選擇要解析的列,而忽略不需要的內容,則可以進一步提高速度。 只需調用settings.selectFields("City");
在處理文件之前,指示解析器僅為“ City
列生成Strings
。
希望這可以幫助。 披露:我是這個圖書館的作者。 它是開源且免費的(Apache v2.0許可證)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.