суббота, 9 июня 2012 г.

Статья 7. CRUD. Retrieve part2.

Доброго времени суток!
В прошлом посте я рассказал о том как извлекать одну запись из NoSQL базы. В случае одной записи все проще простого. А как быть если я хочу вытащить несколько записей? Как сказал бы анатолий Кашперовский, если хочешь вытащить несколько записаей  - просто возьми их:)
Итак, перед тем как я буду описывать конкретные реализации инструментов извлечения, хотелось бы рассказать о концепции мультиселекта. Вытаскивать можно ключи с различной вложеностью (можно вытаскивать ключ и его детей, внуков итп...) слева на право, но не наоборот (правила как в прямом префиксном индексе).
Например дано:

major1/major2/-/minor1/
major1/major3/-/minor1/
major1/major4/-/minor1/
major2/major2/-/minor1/

Можно извлечь по запросу aka like 'major1%':

major1/major2/-/minor1/
major1/major3/-/minor1/
major1/major4/-/minor1/

Но нельзя извлечь по запросу aka like '%major2%'.
major1/major2/-/minor1/
major2/major2/-/minor1/

Надеюсь, что не очень запутал, а если запутал,то надеюсь что дальше будет понятнее.
В Oracle NoSQL DB на данный момент существует 3 способа извлечения множество строк.

multiGet() - самый прямолинейный способ извлечени данных фетчит все и сразу в память. Испоьзует структуру SortedMap, данные умеет возвразать в отсортированном порядке. Требует полного major ключа. Приведу пример.
Дано:
major1/major2/-/minor1/
major1/major2/-/minor2/
major1/major3/-/minor1/

Можно извлечь значения ключей (like 'major1/major2%'):
major1/major2/-/minor1/
major1/major2/-/minor2/
Но нельзя (like 'major1/%'):

major1/major2/-/minor1/
major1/major2/-/minor2/
major1/major3/-/minor1/

multiGetIterator() - умеет возвращать данные пачками (если достаем оч. много данных, будет не камельфо, если за одну итерацию в память у нас уйдет терабайт данных). Данные умеет возвращать в отсортированном порядке. Так же как и multiGet() требует полного major key.

storeIterator() - умеет доставать записи пачками. НЕ требуется полного major ключа достаточно куска major key. Сортировать не умеет. Мой неготивный опыт работы с этим оператором - он не возвращает строк по полному major пути. Почему не заню, скорее всего не до разобрался. Впрочем workaround прост - используем для этого multiGet().

Для упрощения своей работы я создал 2 метода: SelectWhere и SelectWhereFullMajor(опять же таки привет моему полу-реляционному мышлению).

public static void SelectWhere(String sKey,KVStore myStore) {
        Key myKey = ParseKey.ParseKey(sKey);
        try {
            Iterator<KeyValueVersion> myrecords =
                    myStore.storeIterator(Direction.UNORDERED, 0, myKey, null, Depth.PARENT_AND_DESCENDANTS);
            while (myrecords.hasNext()) {
                Key key = myrecords.next().getKey();
                ValueVersion vv = myStore.get(key);
                Value v = vv.getValue();
                data = new String(v.getValue());
                List<String> majorPath1 = key.getMajorPath();
                List<String> minorPath1 = key.getMinorPath();
                System.out.println(majorPath1 + " - " + minorPath1 + ":" + data);
            }
        } catch (RequestTimeoutException re) {
            System.out.println(re.getTimeoutMs());
        } catch (FaultException fe) {
        } finally {
        }
    }


    public static void SelectWhereFullMajor(String sKey,KVStore myStore) {
        Key myKey = ParseKey.ParseKey(sKey);
        try {
            // Initialize Matrix
            SortedMap<Key, ValueVersion> myrecords = null;
            myrecords = myStore.multiGet(myKey, null, Depth.PARENT_AND_DESCENDANTS, Consistency.ABSOLUTE, 1, TimeUnit.DAYS);      
            for (SortedMap.Entry<Key, ValueVersion> entry : myrecords.entrySet()) {
                ValueVersion vv = entry.getValue();
                Value v = vv.getValue();
                Key myKeyOut = entry.getKey();
                String data = new String(v.getValue());
                List<String> majorPath1 = myKeyOut.getMajorPath();
                List<String> minorPath1 = myKeyOut.getMinorPath();
                System.out.println(majorPath1 + " - " + minorPath1 + ":" + data);
            }
        } catch (RequestTimeoutException re) {
            System.out.println(re.getTimeoutMs());
        } catch (FaultException fe) {
        } finally {
        }
    }


при описании метода мы определяем глубину чтения (только указанные ключи, ключи и дети...) 

Если у вас есть какие-либо вопросы по Oracle NoSQL - задавайте в комментах, постараюсь ответить, либо пишите на oracle.nosql@gmail.com.
Пост 6. CRUD. Retrieve.
Доброго времени суток!
Итак едем дальше! Записывать данные в базу мы воде бы как научились. Теперь хочется научиться читать данные из нее. Ну что же это проще простого:)
Начнем с простого получения одной записи. Используя уже созданные пакеты пишем что то вроде того(прости те мое RDBMS-овское прошлое, не смог удержаться от select =)  ):

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.SortedMap;
import java.util.concurrent.TimeUnit;
import oracle.kv.*;

public class RetrieveNoConnect {

    public static String SelectRow(String sKey, KVStore myStore) {
        data = null;
        Key myKey = ParseKey.ParseKey(sKey);
        try {
            ValueVersion vv = myStore.get(myKey);
            Value v = vv.getValue();
            data = new String(v.getValue());
        } catch (RequestTimeoutException re) {
            System.out.println(re.getTimeoutMs());
        } catch (FaultException fe) {
            System.out.println("Unknown error");
        } catch (NullPointerException ne) {
            System.out.println("Key does not exist");
        } finally {
        }
        return data;
    }
}

Тут комментировать впринципе нечего, но я все же прокомментирую:) Простите уж меня за тофтологию. Итак, сначала мы получаем на вход строчку sKey, по которой хотим получить запись, преобразуем ее в тип Key (тип NoSQL DB). Далее получаем переменную ValueVersion (собственно само значение и его версию). Затем берем только то, что нам надо в данной конктетной ситуации - значение. Результат возвращаем. Вот впринципе и все. В завершении main:

import java.io.FileNotFoundException;
import java.io.IOException;
import oracle.kv.KVStore;
import simpleoperation.*;

public class TestClass{

    static String port = "5000";
    static String host = "localhost";
    static String store = "kvstore";

    public static void main(String[] args) throws FileNotFoundException, IOException, InterruptedException {

        OraStore orastore = new OraStore(store, host, port);
        KVStore myStore = orastore.getStore();
        System.out.print(simpleoperation.RetrieveNoConnect.SelectRow("major1/major2/-/minor1/",myStore));         
        myStore.close();
}

Если у вас есть какие-либо вопросы по Oracle NoSQL - задавайте в комментах, постараюсь ответить, либо пишите на oracle.nosql@gmail.com.

пятница, 1 июня 2012 г.


Пост 5. CRUD.CREATE. BULK INSERT.

Доброго времени суток!

Продолжаем наше знакомство с Oracle NoSQL Database. В предыдущей статье мы рассматривали операции создания записей в базе. А что на счет массовой загрузки? Строго говоря ее нет. Но очень хотелось бы иметь возможность загружать данные из фала (начальное формирование базы, миграция с другой платформы). Нет проблем! Давайте напишем свой метод с маджонгом и гейшами! 
Для начала надо договорить о формате входных данных. Пусть это будет, что то вроде:
major1/major2/-/minor1/minor2/: value

Единственное что стоит заметить (а вы надеюсь это уже заметили), тип value в данном примере только String. 
Для начала дополним класс ParseKey методом:
    
public static Value ParseValue(String keysString) {
        String data = keysString.substring(keysString.indexOf(":") + 1);
        Value myValue = Value.createValue(data.getBytes());
        return myValue;
    }

Отлично! Ну и дополняем класс CreateNoConnect методом згрузки из файла:


    public static void LoadFromCSV(String filepath, KVStore myStore)
            throws FileNotFoundException, IOException {
        List<String> majorPath = new ArrayList<>();
        List<String> minorPath = new ArrayList<>();
        FileReader fr = new FileReader(filepath);
        BufferedReader br = new BufferedReader(fr);
        String s;
        while ((s = br.readLine()) != null) {
            Key myKey = ParseKey.ParseKey(s);
            Value myValue = ParseKey.ParseValue(s);
            myStore.put(myKey, myValue);
            majorPath.removeAll(majorPath);
            minorPath.removeAll(minorPath);
        }
        fr.close();
    }

Осталось только сформировать файл входных данных и выполнить main:

    static String port = "5000";
    static String host = "localhost";
    static String store = "kvstore";

    public static void main(String[] args) throws FileNotFoundException, IOException, InterruptedException {

        OraStore orastore = new OraStore(store, host, port);
        KVStore myStore = orastore.getStore();
        simpleoperation.CreateNoConnect.LoadFromFile("C:\\temp\\1.csv", myStore);
        myStore.close();
 }

Если у вас есть какие-либо вопросы по Oracle NoSQL - задавайте в комментах, постараюсь ответить, либо пишите на oracle.nosql@gmail.com.