How you would become an Alt<'a> out of a Job<'a>? Or said others how one becomes one Alt<'a> from many, for example from an Alt<'a>[]?
There is Job.conCollect , which returns Job<'a>, but nothing like Alt.conCollect which would return Alt<'a>
let deleteById (id: ID): Alt<ID> =
// ... delete item ...
let deleteItems (ids: ID[]): Alt<ID[]> =
ids
|> Array.mapJob deleteById
Related
Totally newbie question.
I'm still trying to get a grasp on "Immutable" lists in F#.
Lets assume I have a "Visit" defined as:
module Visit =
type Model =
{
Name: string
}
let init row col cel =
{
Name = sprintf "My Name is row: %d col: %d cel: %d" row col cel
}
Now I define a "Cell" that may or may not have one visit:
module Cell =
type Model =
{
Visit: Visit.Model option
}
let setVisit m =
{ m with Visit = Some( Visit.init 9 9 9) }
and lastly I define a "Column" that has a list of cells:
module Column =
type Model =
{
Appointments: Cell.Model list
}
let updateCell (m:Model) =
let newList = m.Appointments |> List.mapi (fun index cell -> if index = 2 then Cell.setVisit cell else cell)
{m with Appointments = newList }
In the Column module, the "updateCell" function is wired to call Cell.setVisit for the 3rd cell. My intent is to replace the "Name" of the "Visit" held by the 3rd cell. My simple questions are:
Is this the correct way to do this?
If I am replacing the Appointments list, is this not changing the "Column" holding the Appointment List? (The Column is immutable, right? ).
Sorry for my confusion.
TIA
First: yes, this is an acceptable, if inefficient way of doing it for lists. Note that you're rebuilding the whole list on every updateCell call, even though most elements in it are the same.
I don't know how many appointments you expect to have in your model in practice. If it's significantly more than three, and if you're always updating the third one, it would be more efficient to cut the list, then glue it back together:
let newList = List.take 2 m.Appointments # [Cell.setVisit m.Appointments.[2]] # List.drop 3 m.Appointments
This way only the first three elements are rebuilt, and the tail of the list is reused.
However, if you need random-access operations, may I suggest using arrays instead? Sure, they're mutable, but they offer much better performance for random-access operations.
Second: no, the syntax { m with ... } does not change the Column. Instead, it creates a new column - a copy of m, but with all fields listed after with updated to new values.
I'm using the SqlDataConnection type provider and I am trying to figure out the appropriate way to query a table based on query results from a related table.
I initially thought I could do something like this:
let myQuery =
query{
for row in db.StuffTable do
select row
}
let result =
myQuery
|> Seq.filter (fun x -> x.fkTable.contains( y.IsComplete = false ) // this obviously doesn't work
So I then started thinking something like this, but I am not sure:
let reuslt =
query{
for pkRow in pkTable do
for fkRow in fkTable do
where (fkRow.IsComplete = false)
select pkRow
}
What is the correct way?
You probably want to join first on the FK-PK pair of columns, then filter on the desired attributes:
let result = query {
for fkRow in db.FkTable do
join pkRow in db.PkTable on (fkRow.FkColumn = pkRow.PkColumn)
where (pkRow.IsComplete = false)
select fkRow
}
In the rare case where you want a full join (cartesian product of the two tables), you can do this:
let result = query {
for fkRow in db.FkTable do
join pkRow in db.PkTable on (1 = 1)
where (pkRow.IsComplete = false)
select fkRow
}
, or use the query the OP suggested. In this case however, for the latter query to be useful, you'd need to select something from pkTable as well.
How do I do a query expression similar to a SQL IN-query?
I'm trying to do something along these lines:
let customerNumbers = set ["12345"; "23456"; "3456"]
let customerQuery = query {
for c in dataContext.Customers do
where(customerNumbers.Contains(c.CustomerNumber))
select c
}
But I'm getting an error:
System.NotSupportedException: Method 'Boolean Contains(System.String)' has no supported translation to SQL.
Looking at the documentation for query expressions at http://msdn.microsoft.com/en-us/library/hh225374.aspx I should use another query for the contains part but this code doesn't work, the example is broken:
// Select students where studentID is one of a given list.
let idQuery = query { for id in [1; 2; 5; 10] do select id }
query {
for student in db.Student do
where (idQuery.Contains(student.StudentID))
select student
}
idQuery does in fact not contain any "Contains" method.
I have also tried:
let customerNumbers = set ["12345"; "23456"; "3456"]
let customerQuery = query {
for c in dataContext.Customers do
where (query { for x in customerNumbers do exists (c.CustomerNumber=x)})
select r
}
But this gives this error message:
System.NotSupportedException: Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator
I noticed after some more testing that the following also works fine in addition to Gene's suggestion:
let customerNumbers = set ["12345"; "23456"; "3456"]
query {
for customer in dataContext.Customer do
where (query { for x in customerNumbers do contains customer.CustomerNumber})
select customer
}
The problem I believe comes from the way F# Set implements method Contains. It belongs to ICollection interface and this fact somehow upsets LINQ-to-SQL query builder.
If you explicitly force your Contains into the extension method of IEnumerable territory everything gets OK:
let customerNumbers = set ["12345"; "23456"; "3456"]
let customerQuery = query {
for c in dataContext.Customers do
where((customerNumbers :> IEnumerable<string>).Contains(c.CustomerNumber))
select c
}
Or, equivalently, you can add non-LINQ-to-SQL query
let idQuery = query { for id in customerNumbers do select id }
which has no problems with enumerating set yielding seq<string> and then use it for Contains as
....
where (idQuery.Contains(c.CustomerNumber))
....
Or, to begin with, you may keep your customerNumbers as seq:
let customerNumbers = set ["12345"; "23456"; "3456"] |> Set.toSeq
and use it as intuition prompts:
....
where(customerNumbers.Contains(c.CustomerNumber))
....
Hi i have data in a 3 level tree structure. Can I use SOlr JOIN to get the root node when the user searches 3rd level node.
FOr example -
PATIENT1
-> FirstName1
-> LastName1
-> DOCUMENTS1_1
-> document_type1_1
-> document_description1_1
-> document_value1_1
-> CODE_ITEMS1_1_1
-> Code_id1_1_1
-> code1_1_1
-> CODE_ITEMS1_1_1
-> Code_id1_1_2
-> code1_1_2
-> DOCUMENTS1_2
-> document_type1_2
-> document_description1_2
-> document_value1_2
-> CODE_ITEMS1_2_1
-> Code_id1_2_1
-> code1_2_1
-> CODE_ITEMS1_2_2
-> Code_id1_2_2
-> code1_2_2
PATIENT2
-> FirstName2
-> LastName2
-> DOCUMENTS2_1
-> document_type2_1
-> document_description2_1
-> document_value2_1
-> CODE_ITEMS2_1_1
-> Code_id2_1_1
-> code2_1_1
-> CODE_ITEMS2_1_2
-> Code_id2_1_2
-> code2_1_2
I want to search a CODE_ITEM and return all the patient that matches the code items search criteria. How can this be done. Is it possible to implement join twice. First join gives all the documents for the code_item search and the next join gives all the Patient.
Something like in SQL query -
select * from patients where docID (select DOCID from DOCUMENTS where CODEID IN (select CODEID from CODE_ITEMS where CODE LIKE '%SEARCH_TEXT%'))
I really don't know how internally Solr joins work, but knowing that RDB multiple joins are extremely inefficient on large data sets, I'd probably end up writing my own org.apache.solr.handler.component.QueryComponent that would, after doing normal search, get root parent (of course, this approach requires that each child doc has a reference to its root patient).
If you choose to go this path I'll post some examples. I had similar (more complex - ontology) problem in one of my previous Solr projects.
The simpler way to go (simpler when it comes to solving this problem, not the whole approach) is to completely flatten this part of your schema and store all information (documents and code items) into its parent patient and just do a regular search. This is more in line with Solr (you have to look at Solr schema in a different way. It's nothing like your regular RDB normalized schema, Solr encourages data redundancy so that you may search blindingly fast without joins).
Third approach would be to do some joins testing on representative data sets and see how search performance is affected.
In the end, it really depends on your whole setup and requirements (and test results, of course).
EDIT 1:
I did this couple of years back, so you'll have to figure out whether things changed in the mean time.
1. Create custom request handler
To do completely clean job, I suggest you define your own Request handler (in solrconfig.xml) by simply copying the whole section that starts with
<requestHandler name="/select" class="solr.SearchHandler">
...
...
</requestHandler>
and then changing name to something meaningful to your users, like e.g. /searchPatients.
Also, add this part inside:
<arr name="components">
<str>patients</str>
<str>facet</str>
<str>mlt</str>
<str>highlight</str>
<str>stats</str>
<str>debug</str>
</arr>
2. Create custom search component
Add this to your solrconfig:
<searchComponent name="patients" class="org.apache.solr.handler.component.PatientQueryComponent"/>
Create PatientQueryComponent class:
The following source probably has errors since I edited my original source in text editor and posted it without testing, but the important thing is that you get recipe, not finished source, right? I threw out caching, lazy loading, prepare method and left only the basic logic. You'll have to see how the performance will be affected and then tweak the source if needed. My performance was fine, but I had a couple of million documents in total in my index.
public class PatientQueryComponent extends SearchComponent {
...
#Override
public void process(ResponseBuilder rb) throws IOException {
SolrQueryRequest req = rb.req;
SolrQueryResponse rsp = rb.rsp;
SolrParams params = req.getParams();
if (!params.getBool(COMPONENT_NAME, true)) {
return;
}
searcher = req.getSearcher();
// -1 as flag if not set.
long timeAllowed = (long)params.getInt( CommonParams.TIME_ALLOWED, -1 );
DocList initialSearchList = null;
SolrIndexSearcher.QueryCommand cmd = rb.getQueryCommand();
cmd.setTimeAllowed(timeAllowed);
cmd.setSupersetMaxDoc(UNLIMITED_MAX_COUNT);
// fire standard query
SolrIndexSearcher.QueryResult result = new SolrIndexSearcher.QueryResult();
searcher.search(result, cmd);
initialSearchList = result.getDocList();
// Set which'll hold patient IDs
List<String> patientIds = new ArrayList<String>();
DocIterator iterator = initialSearchList.iterator();
int id;
// loop through search results
while(iterator.hasNext()) {
// add your if logic (doc type, ...)
id = iterator.nextDoc();
doc = searcher.doc(id); // , fields) you can try lazy field loading and load only patientID filed value into the doc
String patientId = doc.get("patientID") // field that's in child doc and points to its root parent - patient
patientIds.add(patientId);
}
// All all unique patient IDs in TermsFilter
TermsFilter termsFilter = new TermsFilter();
Term term;
for(String pid : patientIds){
term = new Term("patient_ID", pid); // field that's unique (name) to patient and holds patientID
termsFilter.addTerm(term);
}
// get all patients whose ID is in TermsFilter
DocList patientsList = null;
patientsList = searcher.getDocList(new MatchAllDocsQuery(), searcher.convertFilter(termsFilter), null, 0, 1000);
long totalSize = initialSearchList.size() + patientsList.size();
logger.info("Total: " + totalSize);
SolrDocumentList solrResultList = SolrPluginUtils.docListToSolrDocumentList(patientsList, searcher, null, null);
SolrDocumentList solrInitialList = SolrPluginUtils.docListToSolrDocumentList(initialSearchList, searcher, null, null);
// Add patients to the end of the list
for(SolrDocument parent : solrResultList){
solrInitialList.add(parent);
}
// replace initial results in response
SolrPluginUtils.addOrReplaceResults(rsp, solrInitialList);
rsp.addToLog("hitsRef", patientsList.size());
rb.setResult( result );
}
}
Take a look at this post: http://blog.griddynamics.com/2013/12/grandchildren-and-siblings-with-block.html
Actually you can do it in SOLR 4.5
I'm rewriting a C# library in F# in which most of the classes map one-to-one with database tables (similar to ActiveRecord). I'm considering whether to use records or classes (maybe even DUs?). There's a fair amount of validation in the property setters to maintain invariants. What would be the best way to model this in F#? I don't want an object that violates business logic to be persisted to the database. Any ideas are welcome.
A few additional thoughts...
Is it better to move the invariants to an external 'controller' class? Coming from C# it feels wrong to allow an object that corresponds to a database record to contain anything that can't be saved to the database. I suppose because failing earlier seems better than failing later.
You can have your data in a record, and still keep the validation logic with the data type, by attaching methods to the record:
type Person =
{ First : string;
Last : string; } with
member x.IsValid () =
let hasValue = System.String.IsNullOrEmpty >> not
hasValue x.First && hasValue x.Last
let jeff = { First = "Jeff"; Last = "Goldblum" }
let jerry = { jeff with First = "Jerry" }
let broken = { jerry with Last = "" }
let valid = [jeff; jerry; broken]
|> List.filter (fun x -> x.IsValid())
The copy semantics for records are almost as convenient as setting a property. The validation doesn't happen on property set, but it's easy to filter a list of records down to only the valid ones.
This should actually be a good way for you to handle it. Having your validation logic in the constructor will give you piece of mind later on in your code because the object is immutable. This also opens up multi-threading possibilities.
Immutable Version
type Customer (id, name) =
do // Constructor
if id <= 0 then
raise(new ArgumentException("Invalid ID.", "id"))
elif String.IsNullOrEmpty(name) then
raise(new ArgumentException("Invalid Name.", "name"))
member this.ID
with get() = id
member this.Name
with get() = name
member this.ModifyName value =
new Customer(id, value)
Mutable Version
type Customer (id) =
let mutable name = ""
do // Constructor
if id <= 0 then
raise(new ArgumentException("Invalid ID.", "id"))
member this.ID
with get() = id
member this.Name
with get() = name
and set value =
if String.IsNullOrEmpty(name) then
raise(new ArgumentException("Invalid Name.", "value"))
name <- value
Have you taken a look at my FunctionalNHibernate project? It's designed as a layer on top of nhibernate to let you declaratively map records to a database. It's early days, but it's just about usable:
http://bitbucket.org/robertpi/functionalnhibernate/