在Java中搜索大型csv的最佳/有效方法

时间:2016-08-28 01:06:42

标签: java algorithm csv search

我有一个有1.5K条目的大型csv文件。每个条目代表一个全球城市,名称,纬度和经度。在Java中搜索csv最好,最快捷的方法是什么?我想用所有条目填充ArrayList,但我认为它很慢(除非我错了)。没有这个文件不会增长,几乎100KB。我希望能够输入城市名称并更新搜索结果;但是我可以自己解决这个问题。

4 个答案:

答案 0 :(得分:5)

大约1 MB的1.5K条目文件应该需要几十毫秒。一个1 GB的文件可能需要几十秒而且可能值得为此文件保存一个索引以节省每次重新读取它的时间。

您可以加载到地图中以获得name

的索引

您可以通过NavigableMap添加纬度和经度索引。这将加快按位置查找的速度。

加载文件需要一点时间,但每次从磁盘读取文件要慢得多。

BTW你可以拥有数万亿行的100s TB数据,要在Java中使用这些数据,你必须要有创意。

简而言之,如果它比你的记忆少得多,那就是文件相对较小。

答案 1 :(得分:3)

1.5K行的城市名称,纬度和经度是一个有点大的文件,它是相当小的文件,你读的方式几乎不重要它,只要你不做任何完全不合理的事情,例如使用无缓冲的I / O一次读取一个字节。

所以,我要做的就是我会继续一次读取一行文件,构造行对象,并将它们添加到ArrayList。这可能足够快,您可以在每次搜索后丢弃列表,并在每次搜索时重新加载它。或者,如果你不介意占据一些记忆,你当然可以保留它。

但无论如何,如果出于一些不可思议的原因,性能最终会成为一个问题,我只会担心性能问题。您尚未告诉我们您正在制作的产品的性能要求。没有性能要求,没有测量,所有关于性能的讨论通常都是不合理的恐惧,并且往往会导致过早的优化。

答案 2 :(得分:0)

最快的CSV解析器是univocity-parsers。有很多方法可以解决这个问题,以下内容足够灵活,可以以合适的速度为您提供结果。以下示例使用150MB CSV文件和130万行,并在~1秒内运行搜索:

首先,创建一个public String toString(){ String accountInfo = ""; //creates a String of the account info according to an easily parsed //format for (int counter = 0; counter < accounts.size(); counter++){ if (counter == 0){ accountInfo = accounts.get(counter).getInfo(); } else{ accountInfo += "\n" + accounts.get(counter).getInfo(); } } return accountInfo; } public void saveToFile(){ File customer = new File( name + ".txt"); try { FileWriter custWriter = new FileWriter(customer); BufferedWriter custBuffer = new BufferedWriter(custWriter); custBuffer.write(this.toString()); //commented out when I thought I needed to use a BufferedWriter //custWriter.write(this.toString()); } catch (IOException e) { e.printStackTrace(); } }

这里我们扩展了库中的一个现有的

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.
    }
}

这在我的电脑上产生了以下输出(2015 MacBook Pro):

// 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");

返回的结果如下所示:

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");列生成Strings

希望这会有所帮助。 披露:我是这个图书馆的作者。它是开源和免费的(Apache v2.0许可证)

答案 3 :(得分:-3)

处理大型文本内容时,可能需要进行一些文本操作。

请注意字符串连接。通常使用StringBufferStringBuilder来连接字符串。