How to do an ets table lookup using a secondary key - erlang

I have a table with the following attributes:
SortCode Index Created
SortCode is the primary key and Index is secondary key. Given an Index value, how do I get the associated SortCode value?
I have tried ets:lookup/3 but it takes only a primary key.

There is not such thing as a secondary index in ets. You can do:
full scan using ets:match or ets:select or
make you own reverse index ets table or
use mnesia with added (secondary) index.

Adding to what Hynek -Pichi- Vychodil has said.
There is no solution in ets to fetch record using some other attribute apart from the key. It can be done using mnesia:dirty_index_read().
If you want to use ets only then you can do as above suggestion or follwoing code. Assuming your record pattern is omething like : {"one",1,"27092015"}
Key is "one" but you have to fetch using 1.
FilterSuspCodeFun = fun ({_,I,_}) when I == 1 -> true ; (_) -> false end,
ListData = ets:tab2list(susp_code),
{SortCode,_,created}= lists:filter(FilterSuspCodeFun,ListData),

Related

How to delete a ets entry based on non key part

I have a etc table ‘table’ as {key,[val1,val2]}
I selected this data from the table using
ets:select(table,[{{‘$1','$2'},[],['$$']}]).
[[key,["val1",<<"12">>]],
[key,["val2",<<"6">>]],
[key,["val3",<<"16">>]]]
I want to delete a entry matching the part [val1,val2] using this
ets:select_delete(table,[{{‘$1','$2'},[{'==','$2',["val1",<<"12">>]}],['$$']}]).
0
But still when I run select again I get
ets:select(table,[{{‘$1','$2'},[],['$$']}]).
[[key,["val1",<<"12">>]],
[key,["val2",<<"6">>]],
[key,["val3",<<"16">>]]]
How can I delete this entry based on the non key part?
The ets:select_delete documentation says:
The match specification has to return the atom true if the object is to be deleted. No other return value gets the object deleted. So one cannot use the same match specification for looking up elements as for deleting them.
So try this:
ets:select_delete(table,[{{'$1','$2'},[{'==','$2',["val1",<<"12">>]}],true}]).
ets:select_delete returns the number of records it deleted, so hopefully it should return 1 this time.

Lua 5.0 - iterations over tables ignore duplicate keys even though values are different

Reading the injected comments in the Code Snippet should give enough context.
--| Table |--
QuestData = {
["QuestName"]={
["Quest Descrip"]={8,1686192712},
["Quest Descrip"]={32,1686193248},
["Quest Descrip"]={0,2965579272},
},
}
--| Code Snippet |--
--| gets QuestName then does below |--
if QuestName then
-- (K = QuestName) and (V = the 3 entries below it in the table)
for k,v in pairs(QuestData) do
-- Checks to make sure the external function that obtained the QuestName matches what is in the table before cont
if strlower(k) == strlower(QuestName) then
local index = 0
-- Iterates over the first two pairs - Quest Descrip key and values
for kk,vv in pairs(v) do
index = index + 1
end
-- Iterates over the second two pairs of values
if index == 1 then
for kk,vv in pairs(v) do
-- Sends the 10 digit hash number to the function
Quest:Function(vv[2])
end
end
end
end
end
The issue I'm running into is that Lua will only pick up one of the numbers and ignore the rest. I need all the possible hash numbers regardless of duplicates. The QuestData table ("database") has well over 10,000 entries. I'm not going to go through all of them and remove the duplicates. Besides, the duplicates are there because the same quest can be picked up in more than one location in the game. It's not a duplicate quest but it has a different hash number.
Key is always unique. It is the point of the key, that the key is pointing to unique value and you can't have more keys with same name to point different values. It is by definition by Lua tables.
It is like if you would want to have two variables with same name and different content. It does not make sense ...
The table type implements associative arrays. [...]
Like global variables, table fields evaluate to nil if they are not initialized. Also like global variables, you can assign nil to a table field to delete it. That is not a coincidence: Lua stores global variables in ordinary tables.
Quote from Lua Tables
Hashing in Lua
Based on comments, I update the answer to give some idea about hashing.
You are using hashing usually in low-level languages like C. In Lua, the associative arrays are already hashed somehow in the background, so it will be overkill (especially using SHA or so).
Instead of linked lists commonly used in C, you should just construct more levels of tables to handle collisions (there is nothing "better" in Lua).
And if you want to have it fancy set up some metatables to make it somehow transparent. But from your question, it is really not clear how your data look like and what you really want.
Basically you don't need more than this:
QuestData = {
["QuestName"]={
["Quest Descrip"]={
{8,1686192712},
{32,1686193248},
{0,2965579272},
},
},
}
As Jakuje already mentioned table keys are unique.
But you can store both as a table member like:
QuestData = {
-- "QuestName" must be unique! Of course you can put it into a table member as well
["QuestName"]={
{hash = "Quest Descrip", values = {8,1686192712} },
{hash = "Quest Descrip", values = {32,1686193248} },
{hash = "Quest Descrip", values = {0,2965579272} }
}
}
I'm sure you can organize this in a better way. It looks like a rather confusing concept to me.
You've said you can't "rewrite the database", but the problem is the QuestData table doesn't hold what you think it holds.
Here's your table:
QuestData = {
["QuestName"]={
["Quest Descrip"]={8,1686192712},
["Quest Descrip"]={32,1686193248},
["Quest Descrip"]={0,2965579272},
},
}
But, this is actually like writing...
QuestData["Quest Descrip"] = {8,1686192712}
QuestData["Quest Descrip"] = {32,1686193248}
QuestData["Quest Descrip"] = {0,2965579272}
So the second (and then, third) values overwrite the first. The problem is not that you can't access the table, but that the table doesn't contain the values any more.
You need to find a different way of representing your data.

How do I remove rows of an RDD whose key is not in another RDD?

Let's say I have a PairRDD, students (id, name). I would like to only keep rows where id is in another RDD, activeStudents (id).
The solution I have is to create a PairDD from activeStudents, (id, id), and the do a join with students.
Is there a more elegant way of doing this?
Thats a pretty good solution to start with. If active students is small enough you could collect the ids as a map and then filter with the id presence (this avoids having to a do a shuffle).
Much like you thought, you can do an outer join if both RDDs contain keys and values.
val students: RDD[(Long, String)]
val activeStudents: RDD[Long]
val activeMap: RDD[(Long, Unit)] = activeStudents.map(_ -> ())
val activeWithName: RDD[(Long, String)] =
students.leftOuterJoin(activeMap).flatMapValues {
case (name, Some(())) => Some(name)
case (name, None) => None
}
If you don't have to join those two data sets then you should definitely avoid it.
I had a similar problem recently and I successfully solved it using a broadcasted Set, which I used in UDF to check whether each RDD row (rather value from one of its columns) is in that Set. That UDF is than used as the basis for the filter transformation.
More here: whats-the-most-efficient-way-to-filter-a-dataframe.
Hope this helps. Ask if it's not clear.

Implementing dynamic methods in rails for key/value pair

Let's say I have a database table called 'options' with corresponding model called Option. Structure of this table is simple and as follows ...
id -> primary key, auto increment
name -> key
value -> value for the key
Sample data rows could be as follows ...
id name value
---- ---------------------------- -----------
1 default_view DAILY
2 show_registration_number 0
3 notification_method IMMEDIATE
What I want is that all the options (keys) should be accessible to me as the method names.
For example if do as following ...
#options = Options.find(:all)
is it possible to access the data like #options.default_view which should return me the value as 'DAILY' and similarly #options.show_registration_number which should return the value as 0.
Also if that is possible, whether modification would be permissible like if #options.default_view = 'MONTHLY' and should update the corresponding record in the database.
This will get you almost the answer you were looking for: http://code.dblock.org/how-to-define-enums-in-ruby
It relies on const_missing and assumes that elements of your "enum" are defined as constants, in your case Option::default_view
However, it is easy to see how to adapt this code to use method_missing so that you can do Option.default_view
Another example of this same approach is contained in rails-settings gem, so you can browse this code for the answer you are looking for

erlang - how can I match tuple contents with qlc and mnesia?

I have a mnesia table for this record.
-record(peer, {
peer_key, %% key is the tuple {FileId, PeerId}
last_seen,
last_event,
uploaded = 0,
downloaded = 0,
left = 0,
ip_port,
key
}).
Peer_key is a tuple {FileId, ClientId}, now I need to extract the ip_port field from all peers that have a specific FileId.
I came up with a workable solution, but I'm not sure if this is a good approach:
qlc:q([IpPort || #peer{peer_key={FileId,_}, ip_port=IpPort} <- mnesia:table(peer), FileId=:=RequiredFileId])
Thanks.
Using on ordered_set table type with a tuple primary key like { FileId, PeerId } and then partially binding a prefix of the tuple like { RequiredFileId, _ } will be very efficient as only the range of keys with that prefix will be examined, not a full table scan. You can use qlc:info/1 to examine the query plan and ensure that any selects that are occurring are binding the key prefix.
Your query time will grow linearly with the table size, as it requires scanning through all rows. So benchmark it with realistic table data to see if it really is workable.
If you need to speed it up you should focus on being able to quickly find all peers that carry the file id. This could be done with a table of bag-type with [fileid, peerid] as attributes. Given a file-id you would get all peers ids. With that you could construct your peer table keys to look up.
Of course, you would also need to maintain that bag-type table inside every transaction that change the peer-table.
Another option would be to repeat fileid and add a mnesia index on that column. I am just not that into mnesia's own secondary indexes.

Resources